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