8da080f361c0872fd7e714fd7d3ae790c7fad4ca
[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.*;
5 import java.lang.reflect.*;
6 import edu.berkeley.sbp.chr.*;
7 import edu.berkeley.sbp.misc.*;
8 import edu.berkeley.sbp.meta.*;
9 import edu.berkeley.sbp.util.*;
10 import java.util.*;
11 import java.io.*;
12 import static edu.berkeley.fleet.two.FleetTwoFleet.*;
13
14 public class Verilog {
15
16     public static class SimpleValue implements Value {
17         public final String s;
18         public SimpleValue(String s) { this.s = s; }
19         public SimpleValue(String s, int high, int low) { this.s = s+"["+high+":"+low+"]"; }
20         public Value getBits(int high, int low) { return new SimpleValue(s, high, low); }
21         public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
22         public String getVerilogName() { return s; }
23         public String toString() { return s; }
24     }
25
26     public static interface Action {
27         public String getVerilogAction();
28     }
29
30     public static interface Trigger {
31         public String getVerilogTrigger();
32     }
33
34     public static interface Assignable {
35         public String getVerilogName();
36         public Assignable getAssignableBits(int high, int low);
37     }
38
39     public static interface Value extends Assignable {
40         public String getVerilogName();
41         public Value getBits(int high, int low);
42     }
43
44     public static class ConditionalAction implements Action {
45         public String condition;
46         public Action action;
47         public ConditionalAction(String condition, Action action) {
48             this.condition = condition;
49             this.action = action;
50         }
51         public String toString() { return getVerilogAction(); }
52         public String getVerilogAction() { return "if ("+condition+") begin "+action.getVerilogAction()+" end"; }
53     }
54
55     public static class ConditionalTrigger implements Trigger {
56         public String condition;
57         public Trigger trigger;
58         public ConditionalTrigger(String condition, Trigger trigger) {
59             this.condition = condition;
60             this.trigger = trigger;
61             if (trigger instanceof Module.Port)
62                 ((Module.Port)trigger).hasLatch = true;
63         }
64         public String getVerilogTrigger() {
65             return "&& (("+condition+") ? (1 " + trigger.getVerilogTrigger() + ") : 1)";
66         }
67     }
68
69     public static class SimpleAssignable implements Assignable {
70         public final String s;
71         public SimpleAssignable(String s) { this.s = s; }
72         public String getVerilogName() { return s; }
73         public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
74     }
75
76     public static class AssignAction implements Action {
77         public String left;
78         public String right;
79         public AssignAction(Assignable left, Value right) {
80             this.left = left.getVerilogName();
81             this.right = right.getVerilogName().toString();
82         }
83         public AssignAction(Assignable left, String right) {
84             this.left = left.getVerilogName();
85             this.right = right;
86         }
87         public String getVerilogAction() { return left + "<=" + right + ";"; }
88         public String toString() { return getVerilogAction(); }
89     }
90     
91     public static class SimpleAction implements Action {
92         public final String verilog;
93         public SimpleAction(String verilog) { this.verilog = verilog; }
94         public String getVerilogAction() { return verilog; }
95         public String toString() { return verilog; }
96     }
97
98     public static class Module {
99         public void dump(String prefix) throws IOException {
100             PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/bitfields.v")));
101             pw.println("`define DATAWIDTH                "+WIDTH_WORD);
102             pw.println("`define CODEBAG_SIZE_BITS        "+CBD_SIZE.valmaskwidth);
103             pw.println("`define INSTRUCTION_WIDTH        "+WIDTH_WORD);
104             pw.println("`define packet_token(p)          "+PACKET_TOKEN.verilogVal("p"));
105             pw.println("`define packet_data(p)           "+PACKET_DATA.verilogVal("p"));
106             pw.println("`define packet_dest(p)           "+PACKET_DEST.verilogVal("p"));
107             pw.println("`define instruction_dest(p)      "+DISPATCH_PATH.verilogVal("p"));
108             pw.flush();
109             pw.close();
110             pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
111             dump(pw, true);
112             pw.flush();
113         }
114         public int id = 0;
115         public final String name;
116         public String getName() { return name; }
117         public Port getPort(String name) { return ports.get(name); }
118
119         public HashSet<InstantiatedModule> instantiatedModules = new HashSet<InstantiatedModule>();
120         public final ArrayList<Event> events = new ArrayList<Event>();
121
122         // FIXME: always-alphabetical convention?
123         public final HashMap<String,Port> ports = new HashMap<String,Port>();
124         public final ArrayList<String> portorder = new ArrayList<String>();
125         public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
126         public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
127         
128         public StringBuffer crap = new StringBuffer();
129         public StringBuffer precrap = new StringBuffer();
130         public void addCrap(String s) { crap.append(s); crap.append('\n'); }
131         public void addPreCrap(String s) { precrap.append(s); precrap.append('\n'); }
132         public void addPreCrap0(String s) { precrap.append(s); }
133
134         public Module(String name) {
135             this.name = name;
136         }
137
138         public SourcePort createInputPort(String name, int width) {
139             if (ports.get(name)!=null) throw new RuntimeException();
140             return new SourcePort(name, width, true);
141         }
142         public SourcePort getInputPort(String name) {
143             SourcePort ret = (SourcePort)ports.get(name);
144             if (ret==null) throw new RuntimeException();
145             return ret;
146         }
147         public SinkPort createOutputPort(String name, int width, String resetBehavior) {
148             if (ports.get(name)!=null) throw new RuntimeException();
149             return new SinkPort(name, width, true, resetBehavior);
150         }
151         public SinkPort createWirePort(String name, int width) {
152             if (ports.get(name)!=null) throw new RuntimeException();
153             return new SinkPort(name, width, false, "");
154         }
155         public SourcePort createWireSourcePort(String name, int width) {
156             if (ports.get(name)!=null) throw new RuntimeException();
157             return new SourcePort(name, width, false);
158         }
159         public SinkPort getOutputPort(String name) {
160             SinkPort ret = (SinkPort)ports.get(name);
161             if (ret==null) throw new RuntimeException();
162             return ret;
163         }
164
165         public class StateWire {
166             public final String name;
167             public final boolean initiallyFull;
168             public String getName() { return name; }
169             public Action isFull()  { return new SimpleAction(name+"==1"); }
170             public Action isEmpty() { return new SimpleAction(name+"==0"); }
171             public Action doFill()  { return new SimpleAction(name+"<=1;"); }
172             public Action doDrain() { return new SimpleAction(name+"<=0;"); }
173             public String doReset() { return name+"<="+(initiallyFull?"1":"0")+";"; }
174             public StateWire(String name) { this(name, false); }
175             public StateWire(String name, boolean initiallyFull) {
176                 this.name = name;
177                 this.initiallyFull = initiallyFull;
178                 statewires.put(name, this);
179             }
180             public void dump(PrintWriter pw) {
181                 pw.println("  reg "+name+";");
182                 pw.println("  initial "+name+"="+(initiallyFull?"1":"0")+";");
183             }
184         }
185
186         public class Latch implements Assignable, Value {
187             public final String name;
188             public final int width;
189             public final long initial;
190             public Latch(String name, int width) { this(name, width, 0); }
191             public Latch(String name, int width, long initial) {
192                 this.width = width;
193                 this.name = name;
194                 this.initial = initial;
195                 latches.put(name, this);
196             }
197             public String getVerilogName() { return name; }
198             public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
199             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
200             public String doReset() { return name+"<="+initial+";"; }
201             public void dump(PrintWriter pw) {
202                 pw.println("  reg ["+(width-1)+":0] "+name+";");
203                 pw.println("  initial "+name+"="+initial+";");
204             }
205         }
206
207         public abstract class Port implements Action, Assignable, Trigger {
208             public abstract String doReset();
209             public final String name;
210             public String getName() { return name; }
211             public final int width;
212             public int getWidth() { return width; }
213             public boolean hasLatch = false;
214             public boolean external;
215             public Port(String name, int width, boolean external) {
216                 this.width = width;
217                 this.name = name;
218                 this.external = external;
219                 ports.put(name, this);
220                 if (external)
221                     portorder.add(name);
222             }
223             public String getVerilogName() { return name; }
224             public String getAck() { return name+"_a"; }
225             public String getReq() { return name+"_r"; }
226             public abstract String getInterface();
227             public abstract String getSimpleInterface();
228             public abstract String getDeclaration();
229             public abstract String getAssignments();
230             public abstract void   connect(SinkPort driven);
231         }
232
233         public static class InstantiatedModule {
234             public final Module module;
235             public final Module thisModule;
236             public final int id;
237             public final HashMap<String,Port> ports = new HashMap<String,Port>();
238             public String getName() { return module.getName()+"_"+id; }
239             public InstantiatedModule(Module thisModule, Module module) {
240                 this.thisModule = thisModule;
241                 this.module = module;
242                 this.id = thisModule.id++;
243                 thisModule.instantiatedModules.add(this);
244             }
245             public void dump(PrintWriter pw) {
246                 pw.println("  " + module.getName() + " " + getName() + "(clk, rst ");
247                 for(String s : module.portorder)
248                     pw.println(", " + getPort(s).getSimpleInterface());
249                 pw.println("   );");
250             }
251             public Port getPort(String name) {
252                 return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
253             }
254             public SinkPort getInputPort(String name) {
255                 int width = module.getPort(name).getWidth();
256                 SinkPort port = (SinkPort)ports.get(name);
257                 if (port == null) {
258                     port = thisModule.new SinkPort(getName()+"_"+name, width, false, "");
259                     ports.put(name, port);
260                 }
261                 return port;
262             }
263             public SourcePort getOutputPort(String name) {
264                 int width = module.getPort(name).getWidth();
265                 SourcePort port = (SourcePort)ports.get(name);
266                 if (port == null) {
267                     port = thisModule.new SourcePort(getName()+"_"+name, width, false);
268                     ports.put(name, port);
269                 }
270                 return port;
271             }
272         }
273
274         public class SourcePort extends Port implements Value {
275             public SinkPort driven = null;
276             public SourcePort(String name, int width, boolean external) { 
277                 super(name, width, external); }
278             public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
279             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
280             public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); }
281             public String getVerilogAction() { return getAck() + " <= 1;"; }
282             public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
283             public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
284             public String getDeclaration() {
285                 StringBuffer sb = new StringBuffer();
286                 if (external) {
287                     sb.append("input "  +                 name +"_r;\n");
288                     sb.append("output " +                 name +"_a_;\n");
289                     sb.append("input ["+(width-1)+":0]" + name +";\n");
290                 } else {
291                     sb.append("wire "  +                 name +"_r;\n");
292                     sb.append("wire ["+(width-1)+":0]" + name +";\n");
293                 }
294                 if (!hasLatch) {
295                     sb.append("wire "    +                 name +"_a;\n");
296                 } else {
297                     sb.append("reg "    +                 name +"_a;\n");
298                     sb.append("initial " +                name +"_a = 0;\n");
299                 }
300                 return sb.toString();
301             }
302             public String doReset() { return hasLatch ? name+"_a<=1;" : ""; }
303             public String getAssignments() {
304                 StringBuffer sb = new StringBuffer();
305                 if (external)
306                     sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
307                 if (driven != null) {
308                     sb.append("assign " + driven.name +"_r = " + name + "_r;\n");
309                     sb.append("assign " + name +"_a = " + driven.name + "_a;\n");
310                     sb.append("assign " + driven.name +"   = " + name + ";\n");
311                 }
312                 return sb.toString();
313             }
314             public void connect(SinkPort driven) {
315                 this.driven = driven;
316             }
317         }
318         public class SinkPort extends Port {
319             public boolean forceNoLatch = false;
320             public SinkPort driven = null;
321             public final String resetBehavior;
322             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
323             public String getVerilogAction() { return getReq() + " <= 1;"; }
324             public String getVerilogTrigger() { return " && !" + getReq() + " && !"+getAck(); }
325             public SinkPort(String name, int width, boolean external, String resetBehavior) {
326                 super(name, width, external); this.resetBehavior=resetBehavior; }
327             public String getResetBehavior() { return resetBehavior; }
328             public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
329             public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
330             public String getDeclaration() {
331                 StringBuffer sb = new StringBuffer();
332                 if (external) {
333                     sb.append("output "  +                 name +"_r_;\n");
334                     sb.append("input "   +                 name +"_a;\n");
335                     sb.append("output ["+(width-1)+":0]" + name +"_;\n");
336                 } else {
337                     sb.append("wire "   +                 name +"_a;\n");
338                 }
339
340                 if (forceNoLatch) {
341                     sb.append("reg "    +                  name +"_r;\n");
342                     sb.append("initial " +                 name +"_r = 0;\n");
343                     sb.append("wire   ["+(width-1)+":0]" + name +";\n");
344                 } else if (!hasLatch) {
345                     sb.append("wire "    +                 name +"_r;\n");
346                     sb.append("wire   ["+(width-1)+":0]" + name +";\n");
347                 } else {
348                     sb.append("reg "    +                  name +"_r;\n");
349                     sb.append("initial " +                 name +"_r = 0;\n");
350                     sb.append("reg    ["+(width-1)+":0]" + name +";\n");
351                     sb.append("initial " +                 name +" = 0;\n");
352                 }
353                 return sb.toString();
354             }
355             public String doReset() {
356                 return forceNoLatch
357                     ? name+"_r<=0;"
358                     : hasLatch
359                     ? (name+"_r<=0; "+name+"<=0;")
360                     : "";
361             }
362             public String getAssignments() {
363                 StringBuffer sb = new StringBuffer();
364                 if (external) {
365                     sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
366                     sb.append("assign " +                  name +"_ = " + name + ";\n");
367                 }
368                 if (driven != null) {
369                     sb.append("assign " + driven.name +"_r = " + name + "_r;\n");
370                     sb.append("assign " + name +"_a = " + driven.name + "_a;\n");
371                     sb.append("assign " + driven.name +"   = " + name + ";\n");
372                 }
373                 return sb.toString();
374             }
375             public void connect(SinkPort driven) {
376                 this.driven = driven;
377             }
378         }
379
380         public void dump(PrintWriter pw, boolean fix) {
381             pw.println("`include \"macros.v\"");
382             pw.println("module "+name+"(clk, rst ");
383             for(String name : portorder) {
384                 Port p = ports.get(name);
385                 pw.println("    , " + p.getInterface());
386             }
387             pw.println("   );");
388             pw.println();
389             pw.println("    input clk;");
390             pw.println("    input rst;");
391             for(String name : ports.keySet()) {
392                 Port p = ports.get(name);
393                 pw.println("    " + p.getDeclaration());
394             }
395             for(StateWire sw : statewires.values())
396                 sw.dump(pw);
397             for(Latch l : latches.values())
398                 l.dump(pw);
399             for(String name : ports.keySet()) {
400                 Port p = ports.get(name);
401                 pw.println("    " + p.getAssignments());
402             }
403             for(InstantiatedModule m : instantiatedModules) {
404                 m.dump(pw);
405             }
406             pw.println(precrap);
407             pw.println("always @(posedge clk) begin");
408             pw.println("  if (!rst) begin");
409             for(Latch l : latches.values())
410                 pw.println(l.doReset());
411             for(StateWire sw : statewires.values())
412                 pw.println(sw.doReset());
413             for(Port p : ports.values())
414                 pw.println(p.doReset());
415             pw.println("  end else begin");
416             for(Port p : ports.values()) {
417                 if (p instanceof SourcePort) {
418                     SourcePort ip = (SourcePort)p;
419                     if (ip.hasLatch)
420                         pw.println("if (!"+ip.getReq()+" && "+ip.getAck()+") "+ip.getAck()+"<=0;");
421                 } else {
422                     SinkPort op = (SinkPort)p;
423                     if (op.hasLatch)
424                         pw.println("if ("+op.getReq()+" && "+op.getAck()+") begin "+
425                                    op.getReq()+"<=0; "+
426                                    op.getResetBehavior()+" end");
427                 }
428             }
429             for(Event a : events) a.dump(pw, fix);
430             pw.println("    begin end");
431             pw.println("    end");
432             pw.println("  end");
433
434             pw.println(crap);
435             pw.println("endmodule");
436         }
437
438         public class Event {
439             public Object[]  triggers;
440             public Object[]  actions;
441             public Event(Object[] triggers, Object action) { this(triggers, new Object[] { action }); }
442             public Event(Object[] triggers, Object[] actions) {
443                 Module.this.events.add(this);
444                 this.triggers = triggers;
445                 this.actions = actions;
446                 for(int i=0; i<triggers.length; i++)
447                     if (triggers[i] instanceof Port)
448                         ((Port)triggers[i]).hasLatch = true;
449             }
450             public void dump(PrintWriter pw, boolean fix) {
451                 pw.print("if (1");
452                 for(Object o : triggers) {
453                     if (o instanceof Trigger) pw.print(((Trigger)o).getVerilogTrigger());
454                     else                      pw.print(" && " + o);
455                 }
456                 pw.println(") begin ");
457                 for(Object a : actions) pw.println(((Action)a).getVerilogAction());
458                 if (fix) pw.println("end /*else*/ ");
459                 else     pw.println("end else ");
460             }
461         }
462     }
463 }