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.*;
12 import static edu.berkeley.fleet.two.FleetTwoFleet.*;
14 public class Verilog {
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; }
26 public static class CatValue implements Value {
27 private final Value[] values;
28 public CatValue(Value[] values) { this.values = values; }
29 public Value getBits(int high, int low) {
30 throw new RuntimeException();
32 public Assignable getAssignableBits(int high, int low) {
33 throw new RuntimeException();
35 public String toString() { return getVerilogName(); }
36 public String getVerilogName() {
37 StringBuffer sb = new StringBuffer();
40 for(int i=0; i<values.length; i++) {
41 if (values[i]==null) continue;
42 if (!first) sb.append(", ");
43 sb.append(values[i].getVerilogName());
51 public static interface Action {
52 public String getVerilogAction();
55 public static interface Trigger {
56 public String getVerilogTrigger();
59 public static interface Assignable {
60 public String getVerilogName();
61 public Assignable getAssignableBits(int high, int low);
64 public static interface Value extends Assignable {
65 public String getVerilogName();
66 public Value getBits(int high, int low);
69 public static class ConditionalAction implements Action {
70 public String condition;
72 public ConditionalAction(String condition, Action action) {
73 this.condition = condition;
76 public String toString() { return getVerilogAction(); }
77 public String getVerilogAction() { return "if ("+condition+") begin "+action.getVerilogAction()+" end"; }
80 public static class ConditionalTrigger implements Trigger {
81 public String condition;
82 public Trigger trigger;
83 public ConditionalTrigger(String condition, Trigger trigger) {
84 this.condition = condition;
85 this.trigger = trigger;
86 if (trigger instanceof Module.Port)
87 ((Module.Port)trigger).hasLatch = true;
89 public String getVerilogTrigger() {
90 return "&& (("+condition+") ? (1 " + trigger.getVerilogTrigger() + ") : 1)";
94 public static class SimpleAssignable implements Assignable {
95 public final String s;
96 public SimpleAssignable(String s) { this.s = s; }
97 public String getVerilogName() { return s; }
98 public Assignable getAssignableBits(int high, int low) { return new SimpleValue(s, high, low); }
101 public static class AssignAction implements Action {
104 public AssignAction(Assignable left, Value right) {
105 this.left = left.getVerilogName();
106 this.right = right.getVerilogName().toString();
108 public AssignAction(Assignable left, String right) {
109 this.left = left.getVerilogName();
112 public String getVerilogAction() { return left + "<=" + right + ";"; }
113 public String toString() { return getVerilogAction(); }
116 public static class SimpleAction implements Action {
117 public final String verilog;
118 public SimpleAction(String verilog) { this.verilog = verilog; }
119 public String getVerilogAction() { return verilog; }
120 public String toString() { return verilog; }
123 public static class Module {
124 public void dump(String prefix) throws IOException {
125 PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/bitfields.v")));
126 pw.println("`define DATAWIDTH "+WIDTH_WORD);
127 pw.println("`define CODEBAG_SIZE_BITS "+CBD_SIZE.valmaskwidth);
128 pw.println("`define INSTRUCTION_WIDTH "+WIDTH_WORD);
129 pw.println("`define packet_token(p) "+PACKET_TOKEN.verilogVal("p"));
130 pw.println("`define packet_data(p) "+PACKET_DATA.verilogVal("p"));
131 pw.println("`define packet_dest(p) "+PACKET_DEST.verilogVal("p"));
132 pw.println("`define instruction_dest(p) "+DISPATCH_PATH.verilogVal("p"));
135 pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(prefix+"/"+name+".v")));
138 for(InstantiatedModule m : instantiatedModules)
139 m.module.dump(prefix);
142 public final String name;
143 public String getName() { return name; }
144 public Port getPort(String name) { return ports.get(name); }
146 public HashSet<InstantiatedModule> instantiatedModules = new HashSet<InstantiatedModule>();
147 public final ArrayList<Event> events = new ArrayList<Event>();
149 // FIXME: always-alphabetical convention?
150 public final HashMap<String,Port> ports = new HashMap<String,Port>();
151 public final ArrayList<String> portorder = new ArrayList<String>();
152 public final HashMap<String,StateWire> statewires = new HashMap<String,StateWire>();
153 public final HashMap<String,Latch> latches = new HashMap<String,Latch>();
155 public StringBuffer crap = new StringBuffer();
156 public StringBuffer precrap = new StringBuffer();
157 //public void addCrap(String s) { crap.append(s); crap.append('\n'); }
158 public void addPreCrap(String s) { precrap.append(s); precrap.append('\n'); }
159 public void addPreCrap0(String s) { precrap.append(s); }
161 public Module(String name) {
165 public SourcePort createInputPort(String name, int width) {
166 if (ports.get(name)!=null) throw new RuntimeException();
167 return new SourcePort(name, width, true);
169 public SourcePort getInputPort(String name) {
170 SourcePort ret = (SourcePort)ports.get(name);
171 if (ret==null) throw new RuntimeException();
174 public SinkPort createOutputPort(String name, int width, String resetBehavior) {
175 if (ports.get(name)!=null) throw new RuntimeException();
176 return new SinkPort(name, width, true, resetBehavior);
178 public SinkPort createWirePort(String name, int width) {
179 if (ports.get(name)!=null) throw new RuntimeException();
180 return new SinkPort(name, width, false, "");
182 public SourcePort createWireSourcePort(String name, int width) {
183 if (ports.get(name)!=null) throw new RuntimeException();
184 return new SourcePort(name, width, false);
186 public SinkPort getOutputPort(String name) {
187 SinkPort ret = (SinkPort)ports.get(name);
188 if (ret==null) throw new RuntimeException();
192 public class StateWire {
193 public final String name;
194 public final boolean initiallyFull;
195 public String getName() { return name; }
196 public Action isFull() { return new SimpleAction(name+"==1"); }
197 public Action isEmpty() { return new SimpleAction(name+"==0"); }
198 public Action doFill() { return new SimpleAction(name+"<=1;"); }
199 public Action doDrain() { return new SimpleAction(name+"<=0;"); }
200 public String doReset() { return name+"<="+(initiallyFull?"1":"0")+";"; }
201 public StateWire(String name) { this(name, false); }
202 public StateWire(String name, boolean initiallyFull) {
204 this.initiallyFull = initiallyFull;
205 statewires.put(name, this);
207 public void dump(PrintWriter pw) {
208 pw.println(" reg "+name+";");
209 pw.println(" initial "+name+"="+(initiallyFull?"1":"0")+";");
213 public class Latch implements Assignable, Value {
214 public final String name;
215 public final int width;
216 public final long initial;
217 public Latch(String name, int width) { this(name, width, 0); }
218 public Latch(String name, int width, long initial) {
221 this.initial = initial;
222 latches.put(name, this);
224 public String getVerilogName() { return name; }
225 public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
226 public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
227 public String doReset() { return name+"<="+initial+";"; }
228 public void dump(PrintWriter pw) {
229 pw.println(" reg ["+(width-1)+":0] "+name+";");
230 pw.println(" initial "+name+"="+initial+";");
232 public void connect(SinkPort driven) {
233 driven.latchDriver = this;
237 public abstract class Port implements Action, Assignable, Trigger {
238 public abstract String doReset();
239 public final String name;
240 public String getName() { return name; }
241 public final int width;
242 public int getWidth() { return width; }
243 public boolean hasLatch = false;
244 public boolean external;
245 public Port(String name, int width, boolean external) {
248 this.external = external;
249 ports.put(name, this);
253 public String getVerilogName() { return name; }
254 public String getAck() { return name+"_a"; }
255 public String getReq() { return name+"_r"; }
256 public abstract String getInterface();
257 public abstract String getSimpleInterface();
258 public abstract String getDeclaration();
259 public abstract String getAssignments();
260 public abstract void connect(SinkPort driven);
263 public static class InstantiatedModule {
264 public final Module module;
265 public final Module thisModule;
267 public final HashMap<String,Port> ports = new HashMap<String,Port>();
268 public String getName() { return module.getName()+"_"+id; }
269 public InstantiatedModule(Module thisModule, Module module) {
270 this.thisModule = thisModule;
271 this.module = module;
272 this.id = thisModule.id++;
273 thisModule.instantiatedModules.add(this);
275 public void dump(PrintWriter pw) {
276 pw.println(" " + module.getName() + " " + getName() + "(clk, rst ");
277 for(String s : module.portorder)
278 pw.println(", " + getPort(s).getSimpleInterface());
279 if (module.name.equals("dram")) {
280 pw.println(" , dram_addr");
281 pw.println(" , dram_addr_r");
282 pw.println(" , dram_addr_a");
283 pw.println(" , dram_isread");
284 pw.println(" , dram_write_data");
285 pw.println(" , dram_write_data_push");
286 pw.println(" , dram_write_data_full");
287 pw.println(" , dram_read_data");
288 pw.println(" , dram_read_data_pop");
289 pw.println(" , dram_read_data_empty");
290 pw.println(" , dram_read_data_latency");
292 if (module.name.equals("video")) {
293 pw.println(" , vga_clk");
294 pw.println(" , vga_psave");
295 pw.println(" , vga_hsync");
296 pw.println(" , vga_vsync");
297 pw.println(" , vga_sync");
298 pw.println(" , vga_blank");
299 pw.println(" , vga_r");
300 pw.println(" , vga_g");
301 pw.println(" , vga_b");
302 pw.println(" , vga_clkout");
306 public Port getPort(String name) {
307 return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
309 public SinkPort getInputPort(String name) {
310 int width = module.getPort(name).getWidth();
311 SinkPort port = (SinkPort)ports.get(name);
313 port = thisModule.new SinkPort(getName()+"_"+name, width, false, "");
314 ports.put(name, port);
318 public SourcePort getOutputPort(String name) {
319 int width = module.getPort(name).getWidth();
320 SourcePort port = (SourcePort)ports.get(name);
322 port = thisModule.new SourcePort(getName()+"_"+name, width, false);
323 ports.put(name, port);
329 public class SourcePort extends Port implements Value {
330 public SourcePort(String name, int width, boolean external) {
331 super(name, width, external); }
332 public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
333 public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
334 public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); }
335 public String getVerilogAction() { return getAck() + " <= 1;"; }
336 public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
337 public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
338 public String testBit(int index, boolean value) {
339 return "("+name+"["+index+"]=="+(value?1:0)+")";
341 public String getDeclaration() {
342 StringBuffer sb = new StringBuffer();
344 sb.append("input " + name +"_r;\n");
345 sb.append("output " + name +"_a_;\n");
346 sb.append("input ["+(width-1)+":0]" + name +";\n");
348 sb.append("wire " + name +"_r;\n");
349 sb.append("wire ["+(width-1)+":0]" + name +";\n");
352 sb.append("wire " + name +"_a;\n");
354 sb.append("reg " + name +"_a;\n");
355 sb.append("initial " + name +"_a = 0;\n");
357 return sb.toString();
359 public String doReset() { return hasLatch ? name+"_a<=1;" : ""; }
360 public String getAssignments() {
361 StringBuffer sb = new StringBuffer();
363 sb.append("assign " + name +"_a_ = " + name + "_a;\n");
364 return sb.toString();
366 public void connect(SinkPort driven) {
367 driven.driver = this;
370 public class SinkPort extends Port {
371 public SourcePort driver = null;
372 public boolean forceNoLatch = false;
373 public SinkPort driven = null;
374 public Latch latchDriver = null;
375 public final String resetBehavior;
376 public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
377 public String getVerilogAction() { return getReq() + " <= 1;"; }
378 public String getVerilogTrigger() { return " && !" + getReq() + " && !"+getAck(); }
379 public SinkPort(String name, int width, boolean external, String resetBehavior) {
380 super(name, width, external); this.resetBehavior=resetBehavior; }
381 public String getResetBehavior() { return resetBehavior; }
382 public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
383 public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
384 public String getDeclaration() {
385 StringBuffer sb = new StringBuffer();
387 sb.append("output " + name +"_r_;\n");
388 sb.append("input " + name +"_a;\n");
389 sb.append("output ["+(width-1)+":0]" + name +"_;\n");
391 sb.append("wire " + name +"_a;\n");
394 if (forceNoLatch || latchDriver!=null) {
395 sb.append("reg " + name +"_r;\n");
396 sb.append("initial " + name +"_r = 0;\n");
397 sb.append("wire ["+(width-1)+":0]" + name +";\n");
398 } else if (!hasLatch) {
399 sb.append("wire " + name +"_r;\n");
400 sb.append("wire ["+(width-1)+":0]" + name +";\n");
402 sb.append("reg " + name +"_r;\n");
403 sb.append("initial " + name +"_r = 0;\n");
404 sb.append("reg ["+(width-1)+":0]" + name +";\n");
405 if (!"/*NORESET*/".equals(resetBehavior))
406 sb.append("initial " + name +" = 0;\n");
408 return sb.toString();
410 public String doReset() {
411 return (forceNoLatch||latchDriver!=null)
414 ? (name+"_r<=0; "+("/*NORESET*/".equals(resetBehavior) ? "" : (name+"<=0;")))
417 public String getAssignments() {
418 StringBuffer sb = new StringBuffer();
420 sb.append("assign " + name +"_r_ = " + name + "_r;\n");
421 sb.append("assign " + name +"_ = " + name + ";\n");
423 if (driven != null) {
424 sb.append("assign " + driven.name +"_r = " + name + "_r;\n");
425 sb.append("assign " + name +"_a = " + driven.name + "_a;\n");
426 sb.append("assign " + driven.name +" = " + name + ";\n");
428 if (driver != null) {
429 sb.append("assign " + name +"_r = " + driver.name + "_r;\n");
430 sb.append("assign " + driver.name +"_a = " + name + "_a;\n");
431 sb.append("assign " + name +" = " + driver.name + ";\n");
433 if (latchDriver != null) {
434 sb.append("assign " + name +" = " + latchDriver.name + ";\n");
436 return sb.toString();
438 public void connect(SinkPort driven) {
439 this.driven = driven;
440 throw new RuntimeException();
444 public void dump(PrintWriter pw, boolean fix) {
445 pw.println("`include \"bitfields.v\"");
446 pw.println("module "+name+"(clk, rst ");
447 for(String name : portorder) {
448 Port p = ports.get(name);
449 pw.println(" , " + p.getInterface());
451 if (this.name.equals("root")) {
452 pw.println(" , dram_addr");
453 pw.println(" , dram_addr_r");
454 pw.println(" , dram_addr_a");
455 pw.println(" , dram_isread");
456 pw.println(" , dram_write_data");
457 pw.println(" , dram_write_data_push");
458 pw.println(" , dram_write_data_full");
459 pw.println(" , dram_read_data");
460 pw.println(" , dram_read_data_pop");
461 pw.println(" , dram_read_data_empty");
462 pw.println(" , dram_read_data_latency");
463 pw.println(" , vga_clk");
464 pw.println(" , vga_psave");
465 pw.println(" , vga_hsync");
466 pw.println(" , vga_vsync");
467 pw.println(" , vga_sync");
468 pw.println(" , vga_blank");
469 pw.println(" , vga_r");
470 pw.println(" , vga_g");
471 pw.println(" , vga_b");
472 pw.println(" , vga_clkout");
476 pw.println(" input clk;");
477 pw.println(" input rst;");
478 if (this.name.equals("root")) {
479 pw.println("output [31:0] dram_addr;");
480 pw.println("output dram_addr_r;");
481 pw.println("input dram_addr_a;");
482 pw.println("output dram_isread;");
483 pw.println("output [31:0] dram_write_data;");
484 pw.println("output dram_write_data_push;");
485 pw.println("input dram_write_data_full;");
486 pw.println("input [31:0] dram_read_data;");
487 pw.println("output dram_read_data_pop;");
488 pw.println("input dram_read_data_empty;");
489 pw.println("input [1:0] dram_read_data_latency;");
490 pw.println("input vga_clk;");
491 pw.println("output vga_psave;");
492 pw.println("output vga_hsync;");
493 pw.println("output vga_vsync;");
494 pw.println("output vga_sync;");
495 pw.println("output vga_blank;");
496 pw.println("output [7:0] vga_r;");
497 pw.println("output [7:0] vga_g;");
498 pw.println("output [7:0] vga_b;");
499 pw.println("output vga_clkout;");
501 for(String name : ports.keySet()) {
502 Port p = ports.get(name);
503 pw.println(" " + p.getDeclaration());
505 for(StateWire sw : statewires.values())
507 for(Latch l : latches.values())
509 for(String name : ports.keySet()) {
510 Port p = ports.get(name);
511 pw.println(" " + p.getAssignments());
513 for(InstantiatedModule m : instantiatedModules) {
517 pw.println("always @(posedge clk) begin");
518 pw.println(" if (!rst) begin");
519 for(Latch l : latches.values())
520 pw.println(l.doReset());
521 for(StateWire sw : statewires.values())
522 pw.println(sw.doReset());
523 for(Port p : ports.values())
524 pw.println(p.doReset());
525 pw.println(" end else begin");
526 for(Port p : ports.values()) {
527 if (p instanceof SourcePort) {
528 SourcePort ip = (SourcePort)p;
530 pw.println("if (!"+ip.getReq()+" && "+ip.getAck()+") "+ip.getAck()+"<=0;");
532 SinkPort op = (SinkPort)p;
534 pw.println("if ("+op.getReq()+" && "+op.getAck()+") begin "+
536 op.getResetBehavior()+" end");
539 for(Event a : events) a.dump(pw, fix);
540 pw.println(" begin end");
545 pw.println("endmodule");
549 public Object[] triggers;
550 public Object[] actions;
551 public Event(Object[] triggers, Object action) { this(triggers, new Object[] { action }); }
552 public Event(Object[] triggers, Object[] actions) {
553 Module.this.events.add(this);
554 this.triggers = triggers;
555 this.actions = actions;
556 for(int i=0; i<triggers.length; i++)
557 if (triggers[i] instanceof Port)
558 ((Port)triggers[i]).hasLatch = true;
560 public void dump(PrintWriter pw, boolean fix) {
562 for(Object o : triggers) {
563 if (o instanceof Trigger) pw.print(((Trigger)o).getVerilogTrigger());
564 else pw.print(" && " + o);
566 pw.println(") begin ");
567 for(Object a : actions) if (a!=null) pw.println(((Action)a).getVerilogAction());
568 if (fix) pw.println("end /*else*/ ");
569 else pw.println("end else ");