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