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