enforce ordering on percolated ports
[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                 if (module.name.equals("ddr2")) {
310                     pw.println("    , ddr2_addr");
311                     pw.println("    , ddr2_addr_r");
312                     pw.println("    , ddr2_addr_a");
313                     pw.println("    , ddr2_isread");
314                     pw.println("    , ddr2_write_data");
315                     pw.println("    , ddr2_write_data_push");
316                     pw.println("    , ddr2_write_data_full");
317                     pw.println("    , ddr2_read_data");
318                     pw.println("    , ddr2_read_data_pop");
319                     pw.println("    , ddr2_read_data_empty");
320                     pw.println("    , ddr2_read_data_latency");
321                 }
322                 if (module.name.equals("video")) {
323                     pw.println("    , vga_clk");
324                     pw.println("    , vga_psave");
325                     pw.println("    , vga_hsync");
326                     pw.println("    , vga_vsync");
327                     pw.println("    , vga_sync");
328                     pw.println("    , vga_blank");
329                     pw.println("    , vga_r");
330                     pw.println("    , vga_g");
331                     pw.println("    , vga_b");
332                     pw.println("    , vga_clkout");
333                 }
334                 pw.println("   );");
335             }
336             public Port getPort(String name) {
337                 return (module.ports.get(name) instanceof SinkPort) ? getOutputPort(name) : getInputPort(name);
338             }
339             public SinkPort getInputPort(String name) {
340                 int width = module.getPort(name).getWidth();
341                 SinkPort port = (SinkPort)ports.get(name);
342                 if (port == null) {
343                     port = thisModule.new SinkPort(getName()+"_"+name, width, false, "");
344                     ports.put(name, port);
345                 }
346                 return port;
347             }
348             public SourcePort getOutputPort(String name) {
349                 int width = module.getPort(name).getWidth();
350                 SourcePort port = (SourcePort)ports.get(name);
351                 if (port == null) {
352                     port = thisModule.new SourcePort(getName()+"_"+name, width, false);
353                     ports.put(name, port);
354                 }
355                 return port;
356             }
357         }
358
359         public class SourcePort extends Port implements Value {
360             public SourcePort(String name, int width, boolean external) { 
361                 super(name, width, external); }
362             public Value getBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
363             public Value getBits(Mask mask) { return getBits(mask.valmaskmax, mask.valmaskmin); }
364             public Value invertBits() { return new SimpleValue("~("+getVerilogName()+")"); }
365             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
366             public String getVerilogTrigger() { return " && " + getReq() + " && !"+getAck(); }
367             public String getVerilogAction() { return getAck() + " <= 1;"; }
368             public String getInterface() { return getReq()+", "+getAck()+"_, "+name+""; }
369             public String getSimpleInterface() { return getReq()+", "+getAck()+", "+name+""; }
370             public String testBit(int index, boolean value) {
371                 return "("+name+"["+index+"]=="+(value?1:0)+")";
372             }
373             public String getDeclaration() {
374                 StringBuffer sb = new StringBuffer();
375                 if (external) {
376                     sb.append("input "  +                 name +"_r;\n");
377                     sb.append("output " +                 name +"_a_;\n");
378                     if (width>0)
379                         sb.append("input ["+(width-1)+":0]" + name +";\n");
380                     else
381                         sb.append("input [0:0]" + name +";\n"); // waste a bit, I guess
382                 } else {
383                     sb.append("wire "  +                 name +"_r;\n");
384                     if (width>0)
385                         sb.append("wire ["+(width-1)+":0]" + name +";\n");
386                 }
387                 if (!hasLatch) {
388                     sb.append("wire "    +                 name +"_a;\n");
389                 } else {
390                     sb.append("reg "    +                 name +"_a;\n");
391                     sb.append("initial " +                name +"_a = 0;\n");
392                 }
393                 return sb.toString();
394             }
395             public String doReset() { return hasLatch ? name+"_a<=1;" : ""; }
396             public String getAssignments() {
397                 StringBuffer sb = new StringBuffer();
398                 if (external)
399                     sb.append("assign " +                 name +"_a_ = " + name + "_a;\n");
400                 return sb.toString();
401             }
402             public void connect(SinkPort driven) {
403                 driven.driver = this;
404             }
405         }
406         public class SinkPort extends Port {
407             public SourcePort driver = null;
408             public boolean forceNoLatch = false;
409             public SinkPort driven = null;
410             public Value latchDriver = null;
411             public boolean noDriveLatches = false;
412             public final String resetBehavior;
413             public Assignable getAssignableBits(int high, int low) { return new SimpleValue(getVerilogName(), high, low); }
414             public String getVerilogAction() { return getReq() + " <= 1;"; }
415             public String getVerilogTrigger() { return " && !" + getReq() + " && !"+getAck(); }
416             public SinkPort(String name, int width, boolean external, String resetBehavior) {
417                 super(name, width, external); this.resetBehavior=resetBehavior; }
418             public String getResetBehavior() { return resetBehavior; }
419             public String getInterface() { return name+"_r_, "+name+"_a, "+name+"_"; }
420             public String getSimpleInterface() { return name+"_r, "+name+"_a, "+name; }
421             public String getDeclaration() {
422                 StringBuffer sb = new StringBuffer();
423                 if (external) {
424                     sb.append("output "  +                 name +"_r_;\n");
425                     sb.append("input "   +                 name +"_a;\n");
426                     if (width>0)
427                         sb.append("output ["+(width-1)+":0]" + name +"_;\n");
428                     else
429                         sb.append("output [0:0]" + name +"_;\n"); // waste a bit, I guess
430                 } else {
431                     sb.append("wire "   +                 name +"_a;\n");
432                 }
433
434                 if (forceNoLatch ||  latchDriver!=null) {
435                     sb.append("reg "    +                  name +"_r;\n");
436                     sb.append("initial " +                 name +"_r = 0;\n");
437                     if (width>0)
438                         sb.append("wire   ["+(width-1)+":0]" + name +";\n");
439                 } else if (!hasLatch) {
440                     sb.append("wire "    +                 name +"_r;\n");
441                     if (width>0)
442                         sb.append("wire   ["+(width-1)+":0]" + name +";\n");
443                 } else {
444                     sb.append("reg "    +                  name +"_r;\n");
445                     sb.append("initial " +                 name +"_r = 0;\n");
446                     if (width>0) {
447                         sb.append("reg    ["+(width-1)+":0]" + name +";\n");
448                         if (!"/*NORESET*/".equals(resetBehavior))
449                             sb.append("initial " +                 name +" = 0;\n");
450                     }
451                 }
452                 return sb.toString();
453             }
454             public String doReset() {
455                 return (forceNoLatch||latchDriver!=null||width==0)
456                     ? name+"_r<=0;"
457                     : hasLatch
458                     ? (name+"_r<=0; "+("/*NORESET*/".equals(resetBehavior) ? "" : (name+"<=0;")))
459                     : "";
460             }
461             public String getAssignments() {
462                 StringBuffer sb = new StringBuffer();
463                 if (external) {
464                     sb.append("assign " +                  name +"_r_ = " + name + "_r;\n");
465                     if (width>0)
466                         sb.append("assign " +                  name +"_ = " + name + ";\n");
467                 }
468                 if (driven != null) {
469                     sb.append("assign " + driven.name +"_r = " + name + "_r;\n");
470                     sb.append("assign " + name +"_a = " + driven.name + "_a;\n");
471                     if (width>0)
472                         sb.append("assign " + driven.name +"   = " + name + ";\n");
473                 }
474                 if (driver != null) {
475                     sb.append("assign " + name +"_r = " + driver.name + "_r;\n");
476                     sb.append("assign " + driver.name +"_a = " + name + "_a;\n");
477                     if (width>0 && !noDriveLatches && latchDriver==null)
478                         sb.append("assign " + name +"   = " + driver.name + ";\n");
479                 }
480                 if (latchDriver != null) {
481                     if (width>0)
482                         sb.append("assign " + name +"   = " + latchDriver.getVerilogName() + ";\n");
483                 }
484                 return sb.toString();
485             }
486             public void connect(SinkPort driven) {
487                 this.driven = driven;
488                 throw new RuntimeException();
489             }
490         }
491
492         public void dump(PrintWriter pw, boolean fix) {
493             pw.println("module "+name+"(clk, rst ");
494             for(String name : portorder) {
495                 Port p = ports.get(name);
496                 pw.println("    , " + p.getInterface());
497             }
498             for (InstantiatedModule im : this.instantiatedModules)
499                 for(PercolatedPort pp : im.module.percolatedPorts)
500                     pw.println("    , "+pp.name);
501             if (this.name.equals("root")) {
502                 pw.println("    , vga_clk");
503                 pw.println("    , vga_psave");
504                 pw.println("    , vga_hsync");
505                 pw.println("    , vga_vsync");
506                 pw.println("    , vga_sync");
507                 pw.println("    , vga_blank");
508                 pw.println("    , vga_r");
509                 pw.println("    , vga_g");
510                 pw.println("    , vga_b");
511                 pw.println("    , vga_clkout");
512                 pw.println("    , ddr2_addr");
513                 pw.println("    , ddr2_addr_r");
514                 pw.println("    , ddr2_addr_a");
515                 pw.println("    , ddr2_isread");
516                 pw.println("    , ddr2_write_data");
517                 pw.println("    , ddr2_write_data_push");
518                 pw.println("    , ddr2_write_data_full");
519                 pw.println("    , ddr2_read_data");
520                 pw.println("    , ddr2_read_data_pop");
521                 pw.println("    , ddr2_read_data_empty");
522                 pw.println("    , ddr2_read_data_latency");
523             }
524             pw.println("   );");
525             pw.println();
526             pw.println("    input clk;");
527             pw.println("    input rst;");
528             for (InstantiatedModule im : this.instantiatedModules)
529                 for(PercolatedPort pp : im.module.percolatedPorts) {
530                     pw.print(pp.up ? "output" : "input");
531                     pw.print("  ");
532                     if (pp.width > 1)
533                         pw.print("["+(pp.width-1)+":0]");
534                     pw.print(" ");
535                     pw.print(pp.name);
536                     pw.println(";");
537                 }
538             if (this.name.equals("root")) {
539                 pw.println("output  [31:0] ddr2_addr;");
540                 pw.println("output         ddr2_addr_r;");
541                 pw.println("input          ddr2_addr_a;");
542                 pw.println("output         ddr2_isread;");
543                 pw.println("output  [63:0] ddr2_write_data;");
544                 pw.println("output         ddr2_write_data_push;");
545                 pw.println("input          ddr2_write_data_full;");
546                 pw.println("input   [63:0] ddr2_read_data;");
547                 pw.println("output         ddr2_read_data_pop;");
548                 pw.println("input          ddr2_read_data_empty;");
549                 pw.println("input   [1:0]  ddr2_read_data_latency;");
550                 pw.println("input          vga_clk;");
551                 pw.println("output         vga_psave;");
552                 pw.println("output         vga_hsync;");
553                 pw.println("output         vga_vsync;");
554                 pw.println("output         vga_sync;");
555                 pw.println("output         vga_blank;");
556                 pw.println("output   [7:0] vga_r;");
557                 pw.println("output   [7:0] vga_g;");
558                 pw.println("output   [7:0] vga_b;");
559                 pw.println("output         vga_clkout;");
560             }
561             for(String name : ports.keySet()) {
562                 Port p = ports.get(name);
563                 pw.println("    " + p.getDeclaration());
564             }
565             for(StateWire sw : statewires.values())
566                 sw.dump(pw);
567             for(Latch l : latches.values())
568                 l.dump(pw);
569             for(String name : ports.keySet()) {
570                 Port p = ports.get(name);
571                 pw.println("    " + p.getAssignments());
572             }
573             for(InstantiatedModule m : instantiatedModules) {
574                 m.dump(pw);
575             }
576             pw.println(precrap);
577             pw.println("always @(posedge clk) begin");
578             pw.println("  if (!rst) begin");
579             for(Latch l : latches.values())
580                 pw.println(l.doReset());
581             for(StateWire sw : statewires.values())
582                 pw.println(sw.doReset());
583             for(Port p : ports.values())
584                 pw.println(p.doReset());
585             pw.println("  end else begin");
586             for(Port p : ports.values()) {
587                 if (p instanceof SourcePort) {
588                     SourcePort ip = (SourcePort)p;
589                     if (ip.hasLatch)
590                         pw.println("if (!"+ip.getReq()+" && "+ip.getAck()+") "+ip.getAck()+"<=0;");
591                 } else {
592                     SinkPort op = (SinkPort)p;
593                     if (op.hasLatch)
594                         pw.println("if ("+op.getReq()+" && "+op.getAck()+") begin "+
595                                    op.getReq()+"<=0; "+
596                                    op.getResetBehavior()+" end");
597                 }
598             }
599             for(Event a : events) a.dump(pw, fix);
600             pw.println("    begin end");
601             pw.println("    end");
602             pw.println("  end");
603
604             pw.println(crap);
605             pw.println("endmodule");
606         }
607
608         public class Event {
609             public Object[]  triggers;
610             public Object[]  actions;
611             public Event(Object[] triggers, Object action) { this(triggers, new Object[] { action }); }
612             public Event(Object[] triggers, Object[] actions) {
613                 Module.this.events.add(this);
614                 this.triggers = triggers;
615                 this.actions = actions;
616                 for(int i=0; i<triggers.length; i++)
617                     if (triggers[i] instanceof Port)
618                         ((Port)triggers[i]).hasLatch = true;
619             }
620             public void dump(PrintWriter pw, boolean fix) {
621                 pw.print("if (1");
622                 for(Object o : triggers) {
623                     if (o instanceof Trigger) pw.print(((Trigger)o).getVerilogTrigger());
624                     else                      pw.print(" && " + o);
625                 }
626                 pw.println(") begin ");
627                 for(Object a : actions) if (a!=null) pw.println(((Action)a).getVerilogAction());
628                 if (fix) pw.println("end /*else*/ ");
629                 else     pw.println("end else ");
630             }
631         }
632     }
633 }