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