checkpoint
[slipway.git] / src / edu / berkeley / obits / gui / Gui.java
1 package edu.berkeley.obits.gui;
2
3 import com.atmel.fpslic.*;
4 import edu.berkeley.slipway.*;
5 import static com.atmel.fpslic.FpslicConstants.*;
6 import static com.atmel.fpslic.Fpslic.Util.*;
7 import edu.berkeley.obits.*;
8 import edu.berkeley.obits.device.atmel.*;
9 import java.awt.*;
10 import java.awt.geom.*;
11 import java.awt.event.*;
12 import java.awt.color.*;
13 import org.ibex.util.*;
14 import java.io.*;
15 import java.util.*;
16 import javax.swing.*;
17 import static edu.berkeley.obits.gui.GuiConstants.*;
18
19 public class Gui extends ZoomingPanel implements KeyListener, MouseMotionListener {
20
21     Graphics2D g;
22     G gg;
23
24     Fpslic at40k;
25     FtdiBoard drone;
26
27     private Cell[][] ca = new Cell[128][];
28
29     //public static final Color nonselectedcell = new Color(0x44, 0x44, 0x44);
30     public static final Color nonselectedcell = new Color(0xee, 0xee, 0xee);
31     public static final Color selectedcell    = new Color(0x00, 0x00, 0x00);
32
33     public void writeMode4() {
34         try {
35             final JFileChooser fc = new JFileChooser();
36             int returnVal = fc.showSaveDialog(this);
37             Writer pw = new OutputStreamWriter(new FileOutputStream(fc.getSelectedFile()));
38             drone.writeMode4(pw);
39             pw.flush();
40             pw.close();
41             System.err.println("done writing");
42         } catch (Exception e) {
43             e.printStackTrace();
44         }
45     }
46
47     public void readMode4() {
48         try {
49             final JFileChooser fc = new JFileChooser();
50             int returnVal = fc.showOpenDialog(this);
51             drone.readMode4(new FileInputStream(fc.getSelectedFile()));
52             System.err.println("done reading");
53             repaint();
54         } catch (Exception e) {
55             e.printStackTrace();
56         }
57     }
58
59     public Gui(Fpslic at40k, FtdiBoard drone) {
60         this.at40k = at40k;
61         this.drone = drone;
62         for(int i=0; i<ca.length; i++)
63             ca[i] = new Cell[128];
64         for(int x=7; x<17; x++)
65             for(int y=7; y<17; y++)
66                 new Cell(x-7,y-7, at40k.cell(x, y));
67
68         scan();
69         /*
70         Fpslic.Cell c = at40k.cell(0,0);
71         for(int i=0; i<256; i++) {
72             c.ylut(i);
73             System.out.println(c.printYLut());
74         }
75         */
76     }
77
78     public class Cell {
79         Fpslic.Cell cell;
80         boolean in = false;
81         public boolean xon = false;
82         public boolean yon = false;
83         public boolean xknown = false;
84         public boolean yknown = false;
85         int _x, _y;
86         public Cell(int x, int y, Fpslic.Cell cell) {
87             _x = x;
88             _y = y;
89             ca[_x][_y] = this;
90             this.cell = cell;
91             cells.add(this);
92         }
93         public void clear() {
94             gg.color(in ? selectedcell : nonselectedcell);
95             g.fillRect(0, 0, SIZE, SIZE);
96         }
97         public void draw() {
98
99             drawWires();
100             drawLocal();
101
102             AffineTransform t = g.getTransform();
103
104             drawBuffer();
105             g.transform(rotateInnerTransform());
106             drawMux();
107             drawRegister();
108             drawInternalRouting();
109             g.setTransform(t);
110
111             drawGates();
112             drawBorder();
113         }
114         public void drawBuffer() {
115             /*
116             if (!cell.out_relevant()) return;
117
118             GeneralPath p = new GeneralPath();
119             p.moveTo(24, 61);
120             p.lineTo(22, 68);
121             p.lineTo(29, 66);
122             p.lineTo(24, 61);
123             gg.color(cell.oe() == NONE ? Color.white : Color.green);
124             g.fill(p);
125             gg.color(Color.green);
126             g.draw(p);
127
128             gg.color(Color.magenta);
129             if (cell.oe() == V4) {
130                 gg.line(24, 62, 16, 63);
131             } else if (cell.oe() == H4) {
132                 gg.line(24, 67, 24, 76);
133             }
134             */
135         }
136         public void drawWires() {
137             gg.color(MAGENTA);
138             for(int i=0; i<5; i++)
139                 if (cell.hwire(i).isDriven()) {
140                     gg.color(cell.out(i) ? ORANGE : MAGENTA);
141                     gg.line(0, SIZE-(2*(1+RINGS)+2*i), SIZE, SIZE-(2*(1+RINGS)+2*i));
142                 }
143             for(int i=0; i<5; i++)
144                 if (cell.vwire(i).isDriven()) {
145                     gg.color(cell.out(i) ? ORANGE : MAGENTA);
146                     gg.line(2*(1+RINGS)+2*i, 0, 2*(1+RINGS)+2*i, SIZE);
147                 }
148             if (cell.zi_to_xlut_relevant()) wire(cell.zi(), true);
149             if (cell.zi_to_ylut_relevant()) wire(cell.zi(), false);
150             if (cell.zi_to_xlut_relevant()) wire(cell.wi(), true);
151             if (cell.zi_to_ylut_relevant()) wire(cell.wi(), false);
152         }
153
154         public void wire(int plane, boolean xlut) {
155             if (!(plane >= L0 && plane <= L4 && cell.vx(plane))) return;
156             if (xlut ? xlut_relevant(cell) : cell.ylut_relevant())
157                 route(new P(17 - 2*(plane-L0), 8),
158                       rotateInner(xlut ? new P(38, 18) : new P(64, 18)),
159                       3);
160         }
161
162         public P corner(int corner, int size, int ring) {
163             switch(corner) {
164                 case NW: return new P(0    +2*ring,  size -2*ring);
165                 case SW: return new P(0    +2*ring,  0    +2*ring);
166                 case NE: return new P(size -2*ring,  size -2*ring);
167                 case SE: return new P(size -2*ring,  0    +2*ring);
168                 default: return null;
169             }
170         }
171
172         public void drawInternalRouting() {
173             gg.color(ORANGE);
174             if (cell.fb_relevant()) {
175                 if (cell.f()) {
176                     gg.line(51, 74, 37, 74);
177                     gg.line(37, 74, 51, 12);
178                 } else if (cell.c() == XLUT) {
179                     gg.color(LIGHTRED);
180                     gg.line(33, 52, 51, 52);
181                     gg.line(51, 52, 51, 12);
182                 } else if (cell.c() == YLUT) {
183                     gg.color(LIGHTBLUE);
184                     gg.line(67, 52, 51, 52);
185                     gg.line(51, 52, 51, 12);
186                 } else {
187                     gg.line(51, 56, 41, 56);
188                     gg.line(41, 56, 51, 12);
189                 }
190                 if (xlut_relevant(cell)) {
191                     gg.line(52, 12, XLUT_OUTPUT_POINT.getX(), 12);
192                     gg.line(XLUT_OUTPUT_POINT.getX(), 12, XLUT_OUTPUT_POINT.getX(), 32);
193                 }
194                 if (cell.ylut_relevant()) {
195                     gg.line(52, 12, YLUT_OUTPUT_POINT.getX(), 12);
196                     gg.line(YLUT_OUTPUT_POINT.getX(), 12, YLUT_OUTPUT_POINT.getX(), 32);
197                 }
198             }
199         }
200
201         public void drawLocal() {
202             if (!cell.ylut_relevant() && !xlut_relevant(cell)) return;
203
204             P in = rotateOuter(new P(HOFF, 0));
205             P join = rotateInner(new P(HOFF, CORE_OFFSET));
206             int rot = rot();
207             switch(rot) {
208                 case 0: case 2:
209                     join = new P(in.getX(), join.getY());
210                     break;
211                 case 1: case 3:
212                     join = new P(join.getX(), in.getY());
213                     break;
214             }
215
216             // x-input to cell
217             gg.color(RED);
218             P xi  = corner(cell.xi(), SIZE, 4);
219             if (((cell.xlut_relevant() && cell.xi_to_xlut_relevant()) ||
220                 (cell.ylut_relevant() && cell.xi_to_ylut_relevant()))
221                 && (cell.xi() != NONE) && (cell.xi() < L0 || cell.xi() > L4)
222                 ) {
223                 P xi2 = corner(cell.xi(), SIZE + 2*BEVEL, -1).translate(-BEVEL, -BEVEL);
224                 switch(cell.xi()) {
225                     case NW: case NE:
226                         xi = translate(xi, 0, -3);
227                         xi2 = translate(xi2, 0, -3);
228                         break;
229                     case SW: case SE:
230                         xi = translate(xi, 0, 3);
231                         xi2 = translate(xi2, 0, 3);
232                         break;
233                 }
234                 gg.line(xi2, xi);
235             }
236
237             if (xlut_relevant(cell)) {
238
239                 if (cell.xi_to_xlut_relevant() && xi != null)
240                     route(xi, rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 - CORE_SIZE / 3, 20)), 4);
241
242                 // xlut y-input
243                 gg.color(BLUE);
244                 if (cell.yi_to_xlut_relevant())
245                     route(in, rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 - CORE_SIZE / 6, 20)), 5);
246
247                 // xlut output
248                 int xring = 4;
249                 gg.color(cell.xo() ? ORANGE : LIGHTRED);
250                 P xout = rotateInner(new P(SIZE-CORE_OFFSET-CORE_SIZE+17 - 2, CORE_OFFSET + CORE_SIZE - 3));
251                 if (cell.xo()) {
252                     xout = rotateInner(new P(51, 74));
253                     gg.line(rotateInner(new P(51, 62)), xout);
254                 } else if (cell.xo_relevant()) {
255                     gg.line(rotateInner(XLUT_OUTPUT_POINT), xout);
256                 }
257                 if (cell.xo_relevant(NE)) {
258                     gg.line(corner(NE, SIZE, xring).translate(0, 3), corner(NE, SIZE, 0).translate(0, 3));
259                     route(xout, corner(NE, SIZE, xring).translate(0, 3), xring);
260                 }
261                 if (cell.xo_relevant(NW)) {
262                     gg.line(corner(NW, SIZE, xring).translate(0, 3),  corner(NW, SIZE, 0).translate(0, 3));
263                     route(xout, corner(NW, SIZE, xring).translate(0, 3),  xring);
264                 }
265                 if (cell.xo_relevant(SE)) {
266                     gg.line(corner(SE, SIZE, xring).translate(0, -3), corner(SE, SIZE, 0).translate(0, -3));
267                     route(xout, corner(SE, SIZE, xring).translate(0, -3), xring);
268                 }
269                 if (cell.xo_relevant(SW)) {
270                     gg.line(corner(SW, SIZE, xring).translate(0, -3),  corner(SW, SIZE, 0).translate(0, -3));
271                     route(xout, corner(SW, SIZE, xring).translate(0, -3),  xring);
272                 }
273             }
274
275             if (cell.ylut_relevant()) {
276
277                 // ylut y-input
278                 gg.color(BLUE);
279                 if (cell.yi_to_ylut_relevant())
280                     route(in, rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 + CORE_SIZE / 6, 20)), 5);
281
282                 // ylut x-input
283                 gg.color(RED);
284                 if (xi != null && cell.xi_to_ylut_relevant())
285                     route(xi, rotateInner(new P(SIZE - CORE_OFFSET - CORE_SIZE/2 + CORE_SIZE / 3, 20)), 4);
286
287                 // lines directly from the ylut output to the four neighbors
288                 gg.color(cell.yo() ? ORANGE : LIGHTBLUE);
289                 P yout = rotateInner(new P(SIZE-CORE_OFFSET-CORE_SIZE+51 - 2, CORE_OFFSET + CORE_SIZE - 3));
290                 if (cell.yo()) {
291                     yout = rotateInner(new P(51, 74));
292                     gg.line(rotateInner(new P(51, 62)), yout);
293                 } else if (cell.yo_relevant()) {
294                     gg.line(rotateInner(YLUT_OUTPUT_POINT), yout);
295                 }
296                 if (cell.yo_relevant(NORTH)) route(yout, new P(SIZE-40, SIZE+ 0), 2);
297                 if (cell.yo_relevant(EAST))  route(yout, new P(SIZE+ 0,      40), 2);
298                 if (cell.yo_relevant(SOUTH)) route(yout, new P(     40,       0), 2);
299                 if (cell.yo_relevant(WEST))  route(yout, new P(      0, SIZE-40), 2);
300             }
301
302         }
303
304         private AffineTransform rotateOuterTransform() {
305             int rot = rot();
306             AffineTransform a = new AffineTransform();
307             a.rotate((Math.PI/2) * rot);
308             switch(rot) {
309                 case 0: break;
310                 case 1: a.translate(0,  -SIZE); break;
311                 case 2: a.translate(-SIZE, -SIZE); break;
312                 case 3: a.translate(-SIZE, 0); break;
313             }
314             return a;
315         }
316
317         private P rotateOuter(P p) { return p.transform(rotateOuterTransform()); }
318         private P rotateInner(P p) { return p.transform(rotateInnerTransform()); }
319         private P unRotateInner(P p) { return p.inverseTransform(rotateInnerTransform()); }
320
321         private AffineTransform rotateInnerTransform() {
322             int rot = rot();            
323             AffineTransform a = new AffineTransform();
324             a.translate(SIZE-CORE_SIZE-CORE_OFFSET, CORE_OFFSET);
325             a.rotate((Math.PI/2) * rot);
326             switch(rot) {
327                 case 0: break;
328                 case 1: a.translate(0,  -CORE_SIZE); break;
329                 case 2: a.translate(-CORE_SIZE, -CORE_SIZE); break;
330                 case 3: a.translate(-CORE_SIZE, 0); break;
331             }
332             a.translate(-1 * (SIZE-CORE_SIZE-CORE_OFFSET), -CORE_OFFSET);
333             return a;
334         }
335
336
337         private P project(P p1, int ring) {
338             double north = Math.abs( (SIZE-(ring*2)) - p1.getY() );
339             double south = Math.abs( (     (ring*2)) - p1.getY() );
340             double east  = Math.abs( (SIZE-(ring*2)) - p1.getX() );
341             double west  = Math.abs( (     (ring*2)) - p1.getX() );
342             if (north < south && north < east && north < west) return new P(p1.x,        SIZE-ring*2);
343             else if (south < east && south < west)             return new P(p1.x,        ring*2);
344             else if (east < west)                              return new P(SIZE-ring*2, p1.y);
345             else                                               return new P(ring*2,      p1.y);
346
347         }
348
349         private void route(P p1, P p2, int ring) {
350             int ringpos = ring * 2;
351             P projected = project(p1, ring);
352             gg.line(p1, projected);
353             p1 = projected;
354
355             projected = project(p2, ring);
356             gg.line(p2, projected);
357             p2 = projected;
358
359             if (p1.x==p2.x || p1.y==p2.y) {
360                 gg.line(p1, p2);
361                 return;
362             }
363
364             if ((p1.x==SIZE-ring*2 || p1.x==ring*2) && !(p1.y==SIZE-ring*2 || p1.y==ring*2)) {
365                 P p3 = new P(p1.x, p2.y > SIZE/2 ? SIZE-ring*2 : ring*2);
366                 gg.line(p1, p3);
367                 route(p3, p2, ring);
368             } else if ((p1.y==SIZE-ring*2 || p1.y==ring*2) && !(p1.x==SIZE-ring*2 || p1.x==ring*2)) {
369                 P p3 = new P(p2.x > SIZE/2 ? SIZE-ring*2 : ring*2, p1.y);
370                 gg.line(p1, p3);
371                 route(p3, p2, ring);
372             } else
373                 route(p2, p1, ring);
374         }
375         
376         private int rot() {
377             int rot = 0;
378             switch(cell.yi()) {
379                 case SOUTH: rot = 0; break;
380                 case NORTH: rot = 2; break;
381                 case EAST: rot = 1; break;
382                 case WEST: rot = 3; break;
383                 default: {
384                     // FIXME: choose based on xin
385                     if (cell.north() != null && cell.north().yi()==SOUTH) { rot = 0; break; }
386                     if (cell.south() != null && cell.south().yi()==NORTH) { rot = 2; break; }
387                     if (cell.east()  != null && cell.east().yi()==WEST) { rot = 3; break; }
388                     if (cell.west()  != null && cell.west().yi()==EAST) { rot = 1; break; }
389                 }
390             }
391             return rot;
392         }
393         
394         public void drawGates() {
395             AffineTransform t = g.getTransform();
396             try {
397                 g.translate(SIZE-CORE_SIZE-CORE_OFFSET, CORE_OFFSET);
398                 
399                 int rot = rot();
400                 g.rotate((Math.PI/2) * rot);
401                 switch(rot) {
402                     case 0: break;
403                     case 1: g.translate(0,  -CORE_SIZE); break;
404                     case 2: g.translate(-CORE_SIZE, -CORE_SIZE); break;
405                     case 3: g.translate(-CORE_SIZE, 0); break;
406                 }
407
408                 //gg.color(Color.gray);
409                 //g.drawRect(0, 0, CORE_SIZE, CORE_SIZE);
410                 //g.scale(1, -1);
411
412                 Gate gate = new Muller();
413
414                 g.translate(2,   5f);
415                 if (xlut_relevant(cell))
416                     gate.draw(g,
417                               !xknown ? Color.gray : xon ? Color.red : Color.white,
418                               (xon && xknown) ? Color.white : Color.red);
419                 g.translate(34f, 0f);
420                 if (cell.ylut_relevant())
421                     gate.draw(g,
422                               !yknown ? Color.gray : yon ? Color.blue : Color.white,
423                               (yon && yknown) ? Color.white : Color.blue);
424             } finally {
425                 g.setTransform(t);
426             }
427         }
428         public void drawMux() {
429             if (!cell.c_relevant()) return;
430             gg.color(Color.black);
431             if (xlut_relevant(cell) && (cell.c() == ZMUX || cell.c() == XLUT)) {
432                 gg.color(LIGHTRED);
433                 gg.line(XLUT_OUTPUT_POINT, new P(XLUT_OUTPUT_POINT.getX(), 52));
434                 gg.line(new P(XLUT_OUTPUT_POINT.getX(), 52), new P(51, 52));
435             }
436             if (cell.ylut_relevant() && (cell.c() == ZMUX || cell.c() == YLUT)) {
437                 gg.color(LIGHTBLUE);
438                 gg.line(YLUT_OUTPUT_POINT, new P(YLUT_OUTPUT_POINT.getX(), 52));
439                 gg.line(new P(YLUT_OUTPUT_POINT.getX(), 52), new P(51, 52));
440             }
441             if (cell.c() == ZMUX)
442                 gg.color(ORANGE);
443
444             gg.line(51, 52, 51, 51+23);
445
446             if (cell.register_relevant() && cell.f() && !cell.b()) {
447                 gg.line(51, 56, 60, 56);
448                 gg.line(60, 56, 60, 51+25);
449             } else {
450                 gg.line(51, 51+23, 51, 51+25);
451             }
452
453             if (cell.c() == ZMUX) {
454
455                 gg.color(GREEN);
456                 int plane = cell.zi()+1;
457                 route(unRotateInner(new P(8 + 2*(plane-L0),  76 + 2*(plane-L0))),
458                       new P(51, 20),
459                       3);
460                 gg.line(new P(51, 20), new P(51, 50));
461
462                 GeneralPath p = new GeneralPath();
463                 p.moveTo(45, 50);
464                 p.lineTo(47, 54);
465                 p.lineTo(56, 54);
466                 p.lineTo(58, 50);
467                 p.lineTo(45, 50);
468                 gg.color(WHITE);
469                 gg.g.fill(p);
470
471                 gg.color(ORANGE);
472                 gg.g.draw(p);
473
474             }
475         }
476         public int ccolor() {
477             switch(cell.c()) {
478                 case XLUT: return LIGHTRED;
479                 case YLUT: return LIGHTBLUE;
480                 case ZMUX: return ORANGE;
481             }
482             return BLACK;
483         }
484         public void drawRegister() {
485             if (!cell.register_relevant()) return;
486
487             int dark = ccolor();
488             gg.color(Color.white);
489             g.fillRect(47, 58, 9, 14);
490             gg.color(dark);
491             g.drawRect(47, 58, 9, 14);
492
493             GeneralPath p = new GeneralPath();
494             p.moveTo(56, 70);
495             p.lineTo(53, 68);
496             p.lineTo(56, 66);
497             p.lineTo(56, 70);
498             gg.color(cell.ff_reset_value() ? WHITE : dark);
499             g.fill(p);
500             gg.color(dark);
501             g.draw(p);
502         }
503         public void drawBorder() {
504             gg.color(Color.gray);
505             gg.line(BEVEL, 0, SIZE-BEVEL, 0);
506             gg.line(SIZE, BEVEL, SIZE, SIZE-BEVEL);
507             gg.line(SIZE-BEVEL, SIZE, BEVEL, SIZE);
508             gg.line(0, SIZE-BEVEL, 0, BEVEL);
509             /*            
510             gg.color(0xdddddd);
511             gg.line(0, BEVEL, BEVEL,    0);
512             gg.line(SIZE-BEVEL, 0, SIZE, BEVEL);
513             gg.line(SIZE, SIZE-BEVEL, SIZE-BEVEL, SIZE);
514             gg.line(BEVEL, SIZE, 0, SIZE-BEVEL);
515             */
516         }
517     }
518
519     public void pressed() {
520         dragFrom = oldcell;
521     }
522     public void released() {
523         if (dragFrom == null || oldcell == null) return;
524         if (Math.abs(dragFrom._y - oldcell._y) > 1) return;
525         if (Math.abs(dragFrom._x - oldcell._x) > 1) return;
526         if (dragFrom._x == oldcell._x   && dragFrom._y == oldcell._y+1) oldcell.cell.yi(NORTH);
527         if (dragFrom._x == oldcell._x   && dragFrom._y == oldcell._y-1) oldcell.cell.yi(SOUTH);
528         if (dragFrom._x == oldcell._x+1 && dragFrom._y == oldcell._y)   oldcell.cell.yi(EAST);
529         if (dragFrom._x == oldcell._x-1 && dragFrom._y == oldcell._y)   oldcell.cell.yi(WEST);
530         if (dragFrom._x == oldcell._x+1 && dragFrom._y == oldcell._y+1) oldcell.cell.xi(NE);
531         if (dragFrom._x == oldcell._x+1 && dragFrom._y == oldcell._y-1) oldcell.cell.xi(SE);
532         if (dragFrom._x == oldcell._x-1 && dragFrom._y == oldcell._y+1) oldcell.cell.xi(NW);
533         if (dragFrom._x == oldcell._x-1 && dragFrom._y == oldcell._y-1) oldcell.cell.xi(SW);
534         repaint();
535     }
536     public void drawKeyboard(Image keyboardImage, Graphics2D g) {
537                 int width = 300;
538                 int height = (keyboardImage.getHeight(null) * width) / keyboardImage.getWidth(null);
539                 g.drawImage(keyboardImage,
540                             0, getHeight() - height,
541                             width, getHeight(),
542                             0, 0,
543                             keyboardImage.getWidth(null), keyboardImage.getHeight(null),
544                             null);
545     }
546
547     public void _paint(Graphics2D g) {
548
549         this.g = g;
550         this.gg = new G(g);
551         g.setStroke(new BasicStroke((float)0.5));
552
553         g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
554         g.setRenderingHint(RenderingHints.KEY_RENDERING,    RenderingHints.VALUE_RENDER_QUALITY);
555
556         AffineTransform t  = g.getTransform();
557         for(Cell c : cells) {
558             g.setTransform(t);
559             g.translate(     c._x * SIZE /*+ (10 * (c._x/4))*/,      c._y * SIZE /*+ (10 * (c._y/4))*/);
560             c.clear();
561         }
562         for(Cell c : cells) {
563             g.setTransform(t);
564             g.translate(     c._x * SIZE /*+ (10 * (c._x/4))*/,      c._y * SIZE /*+ (10 * (c._y/4))*/);
565             c.draw();
566         }
567         g.setTransform(t);
568
569         g.setTransform(new AffineTransform());
570
571         gg.color(selectedcell);
572         g.fillRect(getWidth() - 200, 0, 200, 600);
573         gg.color(Color.white);
574         g.drawRect(getWidth() - 200, 0, 200, 600);
575
576         Cell newcell = whichCell(mousex, mousey);
577         int line = 10;
578         g.setFont(new Font("monospaced", 0, 14));
579         if (newcell != null && newcell.cell != null) {
580             g.drawString("selected: " + newcell._x + "," + newcell._y, getWidth() - 200 + 10, (line += 15));
581             g.drawString("    xlut: " + XLUT_EQUATIONS[newcell.cell.xlut() & 0xff], getWidth() - 200 + 10, (line += 15));
582             g.drawString("    ylut: " + YLUT_EQUATIONS[newcell.cell.ylut() & 0xff], getWidth() - 200 + 10, (line += 15));
583             String xi = "??";
584             switch(newcell.cell.xi()) {
585                 case NW : xi = "NW"; break;
586                 case NE : xi = "NE"; break;
587                 case SW : xi = "SW"; break;
588                 case SE : xi = "SE"; break;
589                 case NONE  : xi = "."; break;
590                 default:  xi = "L"+(newcell.cell.xi()-L0); break;
591             }
592             g.drawString("x-in mux: " + xi, getWidth() - 200 + 10, (line += 15));
593
594             String yi = "??";
595             switch(newcell.cell.yi()) {
596                 case NORTH : yi = "NORTH"; break;
597                 case SOUTH : yi = "SOUTH"; break;
598                 case EAST  : yi = "EAST"; break;
599                 case WEST  : yi = "WEST"; break;
600                 case NONE  : yi = "."; break;
601                 default:     yi = "L"+(newcell.cell.yi()-L0); break;
602             }
603             g.drawString("y-in mux: " + yi, getWidth() - 200 + 10, (line += 15));
604
605             g.drawString("w-in mux: " + (newcell.cell.wi()==NONE ? "." : ("L"+(newcell.cell.wi()-L0))),
606                          getWidth() - 200 + 10, (line += 15));
607             g.drawString("z-in mux: " + (newcell.cell.zi()==NONE ? "." : ("L"+(newcell.cell.zi()-L0))),
608                          getWidth() - 200 + 10, (line += 15));
609             g.drawString("t-in mux: ", getWidth() - 200 + 10, (line += 15));
610
611             g.drawString(" set/rst: " + (newcell.cell.ff_reset_value() ? "reset=SET" : "."),
612                          getWidth() - 200 + 10, (line += 15));
613
614             String outs = "";
615             for(int i=0; i<5; i++) outs += (newcell.cell.out(L0+i) ? (i+" ") : ". ");
616             g.drawString("     out: " + outs,
617                          getWidth() - 200 + 10, (line += 15));
618             String hs = "";
619             for(int i=0; i<5; i++) hs += (newcell.cell.hx(L0+i) ? (i+" ") : ". ");
620             g.drawString("  h conn: " + hs,
621                          getWidth() - 200 + 10, (line += 15));
622             String vs = "";
623             for(int i=0; i<5; i++) vs += (newcell.cell.vx(L0+i) ? (i+" ") : ". ");
624             g.drawString("  v conn: " + vs,
625                          getWidth() - 200 + 10, (line += 15));
626             g.drawString("out enab: " + (newcell.cell.oe()==H4 ? "H4" : newcell.cell.oe()==V4 ? "V4" : "."),
627                          getWidth() - 200 + 10, (line += 15));
628             g.drawString("   c-mux: " + (newcell.cell.c()==ZMUX ? "zmux" : newcell.cell.c()==XLUT ? "x-lut" : "y-lut"),
629                          getWidth() - 200 + 10, (line += 15));
630             g.drawString(" fb src: " + (newcell.cell.f() ? "clocked" : "."),
631                          getWidth() - 200 + 10, (line += 15));
632             g.drawString("  bypass: " + (newcell.cell.b() ? "clocked" : "."),
633                          getWidth() - 200 + 10, (line += 15));
634             g.drawString("   x out: " + (newcell.cell.xo() ? (newcell.cell.b() ? "register" : "center") : "."),
635                          getWidth() - 200 + 10, (line += 15));
636             g.drawString("   y out: " + (newcell.cell.yo() ? (newcell.cell.b() ? "register" : "center") : "."),
637                          getWidth() - 200 + 10, (line += 15));
638
639         }
640         if (shiftkey) {
641             drawKeyboard(keyboard2, g);
642         } else switch(lastChar) {
643             case 'x':
644             case 'y':
645             case 'z':
646             case 'w':
647             case 'o':
648             case 'h':
649             case 'v':
650                 drawKeyboard(keyboard3, g);
651                 break;
652             default:
653                 drawKeyboard(keyboard1, g);
654                 break;
655         }
656
657         while (mousebutton) {
658
659             if (dragFrom == null || oldcell == null) break;
660             if (Math.abs(dragFrom._y - oldcell._y) > 1) break;
661             if (Math.abs(dragFrom._x - oldcell._x) > 1) break;
662             g.setTransform(t);
663             if (dragFrom._x == oldcell._x || dragFrom._y == oldcell._y)
664                 gg.color(BLUE);
665             else
666                 gg.color(RED);
667
668             gg.line( oldcell._x * SIZE + SIZE/2,
669                      oldcell._y * SIZE + SIZE/2,
670                      dragFrom._x * SIZE + SIZE/2,
671                      dragFrom._y * SIZE + SIZE/2, 5);
672             break;
673         }
674
675         this.g = null;
676         this.gg = null;
677     }
678     Cell dragFrom = null;
679
680     public void clear() {
681         Graphics2D g = (Graphics2D)getGraphics();
682         //gg.color(Color.black);
683         //gg.color(Color.lightGray);
684         g.clearRect(0, 0, getWidth(), getHeight());
685     }
686
687     public static final P translate(P p, int dx, int dy) {
688         return new P(p.getX()+dx, p.getY()+dy);
689     }
690
691     public Cell whichCell(int x, int y) {
692         P p = new P(x,y);
693         try {
694             p = p.inverseTransform(transform);
695         } catch (Exception e) {
696             e.printStackTrace();
697         }
698         int col = ((int)p.getX()+0) / SIZE;
699         int row = ((int)p.getY()+0) / SIZE;
700         for(Cell c : cells)
701             if (c._x == col && c._y == row)
702                 return c;
703         return null;
704     }
705
706     public static boolean xlut_relevant(Fpslic.Cell c) {
707         return c.xlut_relevant();
708     }
709
710     public void mouseClicked(MouseEvent e) {
711         final Cell c = whichCell(e.getX(), e.getY());
712         if (c==null) return;
713         scan(c);
714     }
715
716     public void scan() {
717         System.out.println("scan");
718         for(int x=2; x<6; x++)
719             for(int y=2; y<6; y++)
720                 if (ca[x][y] != null)
721                     scan(ca[x][y]);
722     }
723     public void scan(final Gui.Cell c) {
724         try {
725             final Fpslic.Cell cell = c.cell;
726             AtmelSerial.scan(at40k, cell, NONE, true);
727             boolean safe = !cell.fb_relevant();
728             if (cell.xo()) safe = false;
729             if (cell.yo()) safe = false;
730             for(int i=0; i<5; i++)
731                 if (cell.out(i))
732                     safe = false;
733             if (safe) {
734                 int oldc = cell.c();
735                 if (cell.xlut_relevant()) {
736                     cell.c(XLUT);
737                     drone.readBus(new BCB(c, XLUT));
738                 }
739                 if (cell.ylut_relevant()) {
740                     cell.c(YLUT);
741                     drone.readBus(new BCB(c, YLUT));
742                 }
743                 cell.c(oldc);
744             } else {
745                 switch(cell.c()) {
746                     case XLUT: if (cell.xlut_relevant()) drone.readBus(new BCB(c, XLUT)); break;
747                     case YLUT: if (cell.ylut_relevant()) drone.readBus(new BCB(c, YLUT)); break;
748                 }
749                 
750             }
751             AtmelSerial.scan(at40k, cell, NONE, false);
752         } catch (IOException e) {
753             throw new RuntimeException(e);
754         }
755     }
756
757
758     int made = 0;
759     private class BCB implements FtdiBoard.ByteCallback {
760         Gui.Cell c;
761         int who;
762         public BCB(Gui.Cell c, int who) {
763             this.who = who; this.c = c;
764             made++;
765             System.out.println("made="+made);
766         }
767         public void call(byte b) throws Exception {
768             System.out.println("callback: " + b);
769             boolean on = (b & 0x80) != 0;
770             c.xknown = false;
771             c.yknown = false;
772             switch(who) {
773                 case YLUT:
774                     c.yknown = true;
775                     c.yon = on;
776                     repaint();
777                     break;
778                 case XLUT:
779                     c.xknown = true;
780                     c.xon = on;
781                     repaint();
782                     break;
783             }
784             made--;
785             System.out.println("made="+made);
786             if (made==0) scan();
787         }
788     }
789
790     // FIXME: 2-input gates?
791     public abstract class Gate {
792         public boolean invert_x;
793         public boolean invert_y;
794         public boolean invert_z;
795         public boolean invert_out;
796         public abstract boolean result(boolean x, boolean y, boolean z);
797         public void draw(Graphics2D g, Color fill, Color stroke) {
798             GeneralPath p = new GeneralPath();
799             makePath(p);
800             g.setColor(fill);
801             g.fill(p);
802             g.setColor(stroke);
803             g.draw(p);
804
805             AffineTransform a = g.getTransform();
806             g.scale(1, -1);
807             g.setColor(Color.white);
808             if (label() != null) g.drawString(label(), 7, -14);
809             g.setTransform(a);
810         }
811         public String label() { return null; }
812         public boolean setLut(int lut) {
813             for(int inverts = 0; inverts < 16; inverts++) {
814                 invert_x   = (inverts & 0x1) != 0;
815                 invert_y   = (inverts & 0x2) != 0;
816                 invert_z   = (inverts & 0x4) != 0;
817                 invert_out = (inverts & 0x8) != 0;
818                 for(int bit=0; bit<8; bit++) {
819                     boolean x = (bit & 0x1) != 0;
820                     boolean y = (bit & 0x2) != 0;
821                     boolean z = (bit & 0x4) != 0;
822                     boolean expect = (lut & (1<<bit)) != 0;
823
824                     // FIXME symmetry issues here....
825                     boolean result = result(x ^ invert_x, y ^ invert_y, z ^ invert_z) ^ invert_out;
826                     if (result == expect) return true;
827                 }
828             }
829             return false;
830         }
831         public abstract void makePath(GeneralPath gp);
832     }
833
834     public class Or extends Gate {
835         public boolean result(boolean x, boolean y, boolean z) { return x || y || z; }
836         public String label() { return "+"; }
837         public void draw(Graphics2D g, Color fill, Color stroke) {
838             AffineTransform at = g.getTransform();
839             g.scale(1, -1);
840             g.translate(0, -40);
841             super.draw(g, fill, stroke);
842             g.setTransform(at);
843         }
844         public void makePath(GeneralPath gp) {
845             gp.moveTo(29.141f, 36.301f);
846             gp.lineTo(29.141f, 36.301f-7.161f);
847             gp.curveTo(27.71f, 11.24f, 23.413f, 9.45f, 14.82f, 0.5f);
848             gp.curveTo(6.229f, 9.45f, 1.932f, 11.24f, 0.5f, 29.141f);
849             gp.lineTo(0.5f, 29.141f+7.161f);
850             float x = 0.5f;
851             float y = 29.141f+7.161f;
852             gp.curveTo(5.729f+x, -1.789f+y,
853                        6.444f+x, -2.686f+y,
854                        14.32f+x, -3.58f+y);
855             gp.curveTo(22.697f, 33.616f, 23.413f, 34.512f, 29.141f, 36.301f);
856         }
857     }
858
859     public class And extends Gate {
860         public boolean result(boolean x, boolean y, boolean z) { return x && y && z; }
861         public String label() { return "&"; }
862         public void makePath(GeneralPath gp) {
863             gp.moveTo(0, 2);
864             gp.lineTo(0, 19);
865             gp.curveTo(0, 27, 3, 35, 13, 35);
866             gp.curveTo(20, 35, 23, 27, 23, 19);
867             gp.lineTo(23, 2);
868             gp.closePath();
869         }
870     }
871
872     public class Muller extends And {
873         public String label() { return "C"; }
874         public void draw(Graphics2D g, Color fill, Color stroke) {
875             super.draw(g, fill, stroke);
876             g.setColor(stroke);
877             g.drawLine(0, 0, 23, 0);
878         }
879     }
880
881     public class Xor extends Or {
882         public boolean result(boolean x, boolean y, boolean z) { return x ^ y ^ z; }
883         public String label() { return "^"; }
884         public void draw(Graphics2D g, Color fill, Color stroke) {
885             super.draw(g, fill, stroke);
886             g.setColor(stroke);
887             AffineTransform at = g.getTransform();
888             g.scale(1, -1);
889             g.translate(0, -40);
890
891             g.translate(0, 4);
892             GeneralPath gp = new GeneralPath();
893             float x = 0.5f;
894             float y = 29.141f+7.161f;
895             gp.moveTo(x,y);
896             gp.curveTo(5.729f+x, -1.789f+y,
897                        6.444f+x, -2.686f+y,
898                        14.32f+x, -3.58f+y);
899             gp.curveTo(22.697f, 33.616f, 23.413f, 34.512f, 29.141f, 36.301f);
900             g.draw(gp);
901
902             g.setTransform(at);
903         }
904     }
905
906     public abstract class Mux extends Gate {
907         public String label() { return "?"; }
908         public void makePath(GeneralPath gp) {
909             gp.moveTo(0, 15);
910             gp.lineTo(2, 23);
911             gp.lineTo(23, 23);
912             gp.lineTo(25, 15);
913             gp.lineTo(0, 15);
914         }
915     }
916
917     public class X_Mux extends Mux {
918         public boolean result(boolean x, boolean y, boolean z) { return x ? y : z; }
919     }
920     public class Y_Mux extends Mux {
921         public boolean result(boolean x, boolean y, boolean z) { return y ? x : z; }
922     }
923     public class Z_Mux extends Mux {
924         public boolean result(boolean x, boolean y, boolean z) { return z ? x : y; }
925     }
926
927
928     public abstract class Buf extends Gate {
929         public void makePath(GeneralPath gp) {
930             gp.moveTo(0, 15);
931             gp.lineTo(13, 35);
932             gp.lineTo(25, 15);
933             gp.lineTo(0, 15);
934         }
935     }
936
937     public class X extends Buf {
938         public boolean result(boolean x, boolean y, boolean z) { return x; }
939     }
940     public class Y extends Buf {
941         public boolean result(boolean x, boolean y, boolean z) { return y; }
942     }
943     public class Z extends Buf {
944         public boolean result(boolean x, boolean y, boolean z) { return z; }
945     }
946
947     private static Image keyboard1 = Toolkit.getDefaultToolkit().createImage("keyboard1.png");
948     private static Image keyboard2 = Toolkit.getDefaultToolkit().createImage("keyboard2.png");
949     private static Image keyboard3 = Toolkit.getDefaultToolkit().createImage("keyboard3.png");
950
951 }