1 package edu.berkeley.slipway;
6 import com.atmel.fpslic.*;
7 import edu.berkeley.abits.*;
8 import org.ibex.util.*;
10 // FEATURE: more state checking (ie must have reset high before uart-mode, etc)
13 * Slipway board (Fpslic via FTDI USB-UART, running <tt>SlipwaySlave.c</tt>)
15 public class SlipwayBoard extends FpslicBoard {
17 // Private Variables //////////////////////////////////////////////////////////////////////////////
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;
26 // Accessors //////////////////////////////////////////////////////////////////////////////////////
28 public InputStream getInputStream() { return in; }
29 public OutputStream getOutputStream() { return out; }
31 /** just a different return type for <tt>getDevice()</tt> */
32 public FpslicDevice getFpslicDevice() { return (FpslicDevice)getDevice(); }
33 public Device getDevice() { return device; }
36 // Methods //////////////////////////////////////////////////////////////////////////////////////
38 /** initialize assuming default USB settings and only one board connected to the system, perform self-test */
39 public SlipwayBoard() throws Exception { this(true); }
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);
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);
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 ");
72 private void boot(Reader r) throws IOException {
74 OutputStream os = new ProgressOutputStream("bootstrap bitstream:", getConfigStream(), total);
75 BufferedReader br = new BufferedReader(r);
78 String s = br.readLine();
81 os.write((byte)Integer.parseInt(s, 2));
82 if ((bytes % 1000)==0) os.flush();
87 private void init(boolean verbose) throws IOException {
88 if (initialized) throw new Error("cannot initialize twice");
90 byte[] bytes = new byte[6];
96 // read any garbage that might be left in the buffer
98 System.arraycopy(bytes, 1, bytes, 0, 5);
99 bytes[5] = in.readByte();
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 ");
117 while(callbacks.size() == 0) Thread.sleep(50);
118 byte b = in.readByte();
119 ByteCallback bc = (ByteCallback)callbacks.remove(0);
124 } catch (Exception e) {
133 // Device //////////////////////////////////////////////////////////////////////////////
135 public class SlipwayFpslicDevice extends FpslicDevice {
136 private final byte[][][] cache = new byte[24][][];
138 // FEATURE: autodetect width/height by querying device id from the chip
139 public SlipwayFpslicDevice(int width, int height) {
140 super(width, height);
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];
148 public synchronized void mode4(int z, int y, int x, int d) {
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);
159 } catch (IOException e) {
160 throw new RuntimeException(e);
163 public synchronized void flush() {
165 SlipwayBoard.this.flush();
166 } catch (Exception e) {
167 throw new RuntimeException(e);
173 // Callbacks //////////////////////////////////////////////////////////////////////////////
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;
180 private void enqueue(ByteCallback bcb) {
183 while (callbacks.size() >= CALLBACK_LIMIT) {
186 } catch (Exception e) {
187 throw new RuntimeException(e);
193 public static abstract class ByteCallback {
195 public abstract void call(byte b) throws Exception;
198 /** synchronously returns the number of interrupts triggered since the last call to <tt>readInterruptCount()</tt> */
199 public synchronized int readInterruptCount() {
201 ByteCallback bc = new ByteCallback() {
202 public synchronized void call(byte b) throws Exception {
205 ((in.read() & 0xff) << 16) |
206 ((in.read() & 0xff) << 8) |
207 ((in.read() & 0xff) << 0);
209 ((in.read() & 0xff) << 24) |
210 ((in.read() & 0xff) << 16) |
211 ((in.read() & 0xff) << 8) |
212 ((in.read() & 0xff) << 0);
223 } catch (Exception e) { throw new RuntimeException(e); }
226 /** returns the number of milliseconds elapsed between the previous call to readInterruptCount() and the one before it */
227 public synchronized int readInterruptCountTime() {
231 /** reads the values on the 8-bit bus connecting the fpga to the AVR */
232 public synchronized void readFpgaData(ByteCallback bc) throws IOException {
239 // Pin Implementations //////////////////////////////////////////////////////////////////////////////
241 private int dbits = 0;
252 protected void flush() {
254 if (out!=null) out.flush();
255 ftdiuart.getOutputStream().flush();
256 } catch (Exception e) {
257 throw new RuntimeException(e);
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; }
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);
273 ftdiuart.dbus_mode(dmask);
278 protected void setDBusLine() throws IOException {
279 OutputStream os = ftdiuart.getOutputStream();
280 os.write((byte)dbits);
282 protected void clearDBusLines() throws IOException {
286 protected void setDBusLine(int bit, boolean val) throws IOException {
287 dbits = val ? (dbits | (1 << bit)) : (dbits & (~(1 << bit)));
290 protected void releaseConPin() throws IOException {
292 ftdiuart.dbus_mode(dmask);
295 protected void conPin(boolean on) throws IOException {
297 ftdiuart.dbus_mode(dmask);
301 public void close() throws IOException {
302 // switching to uart mode will implicitly release AVRRST
305 ftdiuart.uart_and_cbus_mode(1<<1, 1<<1);
308 protected void purge() throws IOException {
313 // Util //////////////////////////////////////////////////////////////////////////////
315 private static String pad(int i, String s) {
316 if (s.length()>i) return s;
317 return "0"+pad((i-1),s);
319 private static String pad(String s, int i) {
320 if (s.length() >= i) return s;
321 return "0"+pad(s, i-1);