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