updates that were lying around but never got checked in; includes reorg of gui
[slipway.git] / src / edu / berkeley / slipway / SlipwayBoard.java
1 package edu.berkeley.slipway;
2
3 import java.io.*;
4 import java.util.*;
5 import com.ftdi.usb.*;
6 import com.atmel.fpslic.*;
7 import edu.berkeley.abits.*;
8 import org.ibex.util.*;
9
10 // FEATURE: more state checking (ie must have reset high before uart-mode, etc)
11
12 /**
13  * Slipway board (Fpslic via FTDI USB-UART, running <tt>SlipwaySlave.c</tt>)
14  */
15 public class SlipwayBoard extends FpslicBoard {
16
17     // Private Variables //////////////////////////////////////////////////////////////////////////////
18
19     private final DataInputStream in;
20     private final DataOutputStream out;
21     private final FpslicDevice device;
22     private final FtdiUart ftdiuart;
23     private       boolean initialized = false;
24
25
26     // Accessors //////////////////////////////////////////////////////////////////////////////////////
27
28     public InputStream getInputStream() { return in; }
29     public OutputStream getOutputStream() { return out; }
30
31     /** just a different return type for <tt>getDevice()</tt> */
32     public FpslicDevice getFpslicDevice() { return (FpslicDevice)getDevice(); }
33     public Device getDevice() { return device; }
34
35
36     // Methods //////////////////////////////////////////////////////////////////////////////////////
37
38     /** initialize assuming default USB settings and only one board connected to the system, perform self-test */
39     public SlipwayBoard() throws Exception { this(true); }
40
41     /** initialize assuming default USB settings and only one board connected to the system */
42     public SlipwayBoard(boolean selfTest) throws Exception {
43         this(new FtdiUart(0x6666, 0x3133, 1500 * 1000/2), selfTest);
44     }
45
46     /** initialize with a custom USB interface */
47     public SlipwayBoard(FtdiUart ftdiuart, boolean selfTest) throws Exception {
48         this.ftdiuart = ftdiuart;
49         device = new SlipwayFpslicDevice(24, 24);
50         String bstFile = this.getClass().getName();
51         bstFile = bstFile.substring(0, bstFile.lastIndexOf('.'));
52         bstFile = bstFile.replace('.', '/')+"/slipway_drone.bst";
53         if (selfTest) selfTest();
54         boot(new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream(bstFile)));
55         in = new DataInputStream(ftdiuart.getInputStream());
56         out = new DataOutputStream(ftdiuart.getOutputStream());
57         for(int i=0; i<255; i++) out.write(0);
58         out.flush();
59         init(selfTest);
60     }
61
62     private void selfTest() throws IOException {
63         System.err.print("smoke check: ");
64         selfTest(new edu.berkeley.abits.Board.SelfTestResultListener() {
65                 public void reportTestResult(int testNumber, int totalNumberOfTests, boolean didPass) {
66                     System.err.print(didPass ? " \033[32m[pass]\033[0m " : " \033[31m[FAIL]\033[0m ");
67                 }
68             });
69         System.err.println();
70     }
71     
72     private void boot(Reader r) throws IOException {
73         int total = 75090/9;
74         OutputStream os = new ProgressOutputStream("bootstrap bitstream:", getConfigStream(), total);
75         BufferedReader br = new BufferedReader(r);
76         int bytes = 0;
77         while(true) {
78             String s = br.readLine();
79             if (s==null) break;
80             bytes++;
81             os.write((byte)Integer.parseInt(s, 2));
82             if ((bytes % 1000)==0) os.flush();
83         }
84         os.close();
85     }
86
87     private void init(boolean verbose) throws IOException {
88         if (initialized) throw new Error("cannot initialize twice");
89         initialized = true;
90         byte[] bytes = new byte[6];
91         int i=0;
92
93         out.write(0);
94         out.flush();
95
96         // read any garbage that might be left in the buffer
97         while(true) {
98             System.arraycopy(bytes, 1, bytes, 0, 5);
99             bytes[5] = in.readByte();
100             i++;
101             if (verbose) System.err.print("\rsignature: read \"" + new String(bytes) + "\"                   ");
102             if (bytes[0] == (byte)'O' &&
103                 bytes[1] == (byte)'B' &&
104                 bytes[2] == (byte)'I' &&
105                 bytes[3] == (byte)'T' &&
106                 bytes[4] == (byte)'S') {
107                 if (verbose) System.err.println("\rsignature: got proper signature                  ");
108                 purge();
109                 break;
110             }
111         }
112
113         new Thread() {
114             public void run() {
115                 while(true) {
116                     try {
117                         while(callbacks.size() == 0) Thread.sleep(50);
118                         byte b = in.readByte();
119                         ByteCallback bc = (ByteCallback)callbacks.remove(0);
120                         bc.call(b);
121                         synchronized(lock) {
122                             lock.notifyAll();
123                         }
124                     } catch (Exception e) {
125                         e.printStackTrace();
126                     }
127                 }
128             }
129         }.start();
130     }
131
132
133     // Device //////////////////////////////////////////////////////////////////////////////
134
135     public class SlipwayFpslicDevice extends FpslicDevice {
136         private final byte[][][] cache = new byte[24][][];
137
138         // FEATURE: autodetect width/height by querying device id from the chip
139         public SlipwayFpslicDevice(int width, int height) {
140             super(width, height);
141         }
142
143         public synchronized byte mode4(int z, int y, int x) {
144             if (cache[x]==null) return 0;
145             if (cache[x][y]==null) return 0;
146             return cache[x][y][z];
147         }
148         public synchronized void mode4(int z, int y, int x, int d) {
149             try {
150                 if (cache[x & 0xff]==null) cache[x & 0xff] = new byte[24][];
151                 if (cache[x & 0xff][y & 0xff]==null) cache[x & 0xff][y & 0xff] = new byte[256];
152                 cache[x & 0xff][y & 0xff][z & 0xff] = (byte)(d & 0xff);
153                 
154                 out.writeByte(1);
155                 out.writeByte(z);
156                 out.writeByte(y);
157                 out.writeByte(x);
158                 out.writeByte(d);
159             } catch (IOException e) {
160                 throw new RuntimeException(e);
161             }
162         }
163         public synchronized void flush() {
164             try {
165                 SlipwayBoard.this.flush();
166             } catch (Exception e) {
167                 throw new RuntimeException(e);
168             }
169         }
170     }
171
172
173     // Callbacks //////////////////////////////////////////////////////////////////////////////
174
175     private static final int CALLBACK_LIMIT = 40;
176     private Vector callbacks = new Vector();
177     private Object lock = new Object();
178     private int timer = 0;
179
180     private void enqueue(ByteCallback bcb) {
181         synchronized(lock) {
182             try {
183                 while (callbacks.size() >= CALLBACK_LIMIT) {
184                     lock.wait(100);
185                 }
186             } catch (Exception e) {
187                 throw new RuntimeException(e);
188             }
189         }
190         callbacks.add(bcb);
191     }
192
193     public static abstract class ByteCallback {
194         public int result;
195         public abstract void call(byte b) throws Exception;
196     }
197
198     /** synchronously returns the number of interrupts triggered since the last call to <tt>readInterruptCount()</tt> */
199     public synchronized int readInterruptCount() {
200         try {
201             ByteCallback bc = new ByteCallback() {
202                     public synchronized void call(byte b) throws Exception {
203                         result =
204                             ((b & 0xff) << 24) |
205                             ((in.read() & 0xff) << 16) |
206                             ((in.read() & 0xff) << 8) |
207                             ((in.read() & 0xff) << 0);
208                         timer =
209                             ((in.read() & 0xff) << 24) |
210                             ((in.read() & 0xff) << 16) |
211                             ((in.read() & 0xff) << 8) |
212                             ((in.read() & 0xff) << 0);
213                         this.notify();
214                     }
215                 };
216             synchronized(bc) {
217                 enqueue(bc);
218                 out.writeByte(3);
219                 out.flush();
220                 bc.wait();
221             }
222             return bc.result;
223         } catch (Exception e) { throw new RuntimeException(e); }
224     }
225
226     /** returns the number of milliseconds elapsed between the previous call to readInterruptCount() and the one before it */
227     public synchronized int readInterruptCountTime() {
228         return timer;
229     }
230
231     /** reads the values on the 8-bit bus connecting the fpga to the AVR */
232     public synchronized void readFpgaData(ByteCallback bc) throws IOException {
233         enqueue(bc);
234         out.writeByte(2);
235         out.flush();
236     }
237
238
239     // Pin Implementations //////////////////////////////////////////////////////////////////////////////
240
241     private int dbits = 0;
242     private int dmask =
243         (1<<0) |
244         (1<<1) |
245         (1<<2) |
246         //(1<<3) |
247         //(1<<4) |
248         (1<<5) |
249         (1<<6) |
250         (1<<7);
251
252     protected void flush() {
253         try {
254             if (out!=null) out.flush();
255             ftdiuart.getOutputStream().flush(); 
256         } catch (Exception e) {
257             throw new RuntimeException(e);
258         }
259     }
260
261     protected void avrrstPin(boolean on)     throws IOException { setDBusLine(7, on); }
262     protected void cclkPin(boolean on)       throws IOException { setDBusLine(6, on); }
263     protected void configDataPin(boolean on) throws IOException { setDBusLine(5, on); }
264     protected boolean initPin()              throws IOException { flush(); return (ftdiuart.readPins() & (1<<4))!=0; }
265
266     // tricky: RESET has a weak pull-up, and is wired to a CBUS line.  So,
267     //         we can pull it down (assert reset) from uart-mode, or we can
268     //         let it float upward from either mode.
269     protected void resetPin(boolean on) throws IOException {
270         ftdiuart.uart_and_cbus_mode(1<<1, on ? (1<<1) : 0);
271         flush();
272         if (on) {
273             ftdiuart.dbus_mode(dmask);
274             flush();
275         }
276     }
277
278     protected void setDBusLine() throws IOException {
279         OutputStream os = ftdiuart.getOutputStream();
280         os.write((byte)dbits);
281     }
282     protected void clearDBusLines() throws IOException {
283         dbits = 0;
284         setDBusLine();
285     }
286     protected void setDBusLine(int bit, boolean val) throws IOException {
287         dbits = val ? (dbits | (1 << bit)) : (dbits & (~(1 << bit)));
288         setDBusLine();
289     }
290     protected void releaseConPin() throws IOException {
291         dmask &= ~(1<<0);
292         ftdiuart.dbus_mode(dmask);
293         flush();
294     }
295     protected void conPin(boolean on) throws IOException {
296         dmask |= (1<<0);
297         ftdiuart.dbus_mode(dmask);
298         setDBusLine(0, on);
299         flush();
300     }
301     public void close() throws IOException {
302         // switching to uart mode will implicitly release AVRRST
303         avrrstPin(false);
304         ftdiuart.purge();
305         ftdiuart.uart_and_cbus_mode(1<<1, 1<<1);
306         ftdiuart.purge();
307     }
308     protected void purge() throws IOException {
309         ftdiuart.purge();
310     }
311     
312
313     // Util //////////////////////////////////////////////////////////////////////////////
314
315     private static String pad(int i, String s) {
316         if (s.length()>i) return s;
317         return "0"+pad((i-1),s);
318     }
319     private static String pad(String s, int i) {
320         if (s.length() >= i) return s;
321         return "0"+pad(s, i-1);
322     }
323 }
324