ML509: use urjtag's fjmem block as the debug controller (JtagConnectedFpga).
[fleet.git] / src / edu / berkeley / fleet / fpga / JtagConnectedFpga.java
diff --git a/src/edu/berkeley/fleet/fpga/JtagConnectedFpga.java b/src/edu/berkeley/fleet/fpga/JtagConnectedFpga.java
new file mode 100644 (file)
index 0000000..7d14117
--- /dev/null
@@ -0,0 +1,240 @@
+package edu.berkeley.fleet.fpga;
+import edu.berkeley.fleet.fpga.*;
+import edu.berkeley.fleet.api.*;
+import java.io.*;
+import static edu.berkeley.fleet.util.BitManipulations.*;
+import edu.berkeley.fleet.api.*;
+import edu.berkeley.sbp.util.ANSI;
+import java.io.*;
+import java.net.*;
+import edu.berkeley.fleet.util.*;
+import java.util.*;
+import java.util.concurrent.*;
+import static edu.berkeley.fleet.two.FleetTwoFleet.*;
+import static edu.berkeley.fleet.api.Instruction.Set.*;
+import static edu.berkeley.fleet.api.Predicate.*;
+import static edu.berkeley.fleet.api.Instruction.*;
+import com.sun.electric.tool.io.ExecProcess;
+
+public abstract class JtagConnectedFpga extends Fpga {
+
+    protected JtagConnectedFpga() throws IOException {
+    }
+
+    public FleetProcess run(Instruction[] instructions) {
+        try {
+            return new JtagConnectedFpgaClient(this, "none", instructions);
+        } catch (Exception e) { throw new RuntimeException(e); }
+    }
+
+    public static class JtagConnectedFpgaClient extends FleetProcess {
+
+        private Fpga fpga;
+        private BlockingQueue<BitVector> queue = new LinkedBlockingQueue<BitVector>();
+        public PrintWriter pwjtag;
+        private Semaphore semaphore = new Semaphore(0);
+        private Semaphore peekSemaphore = new Semaphore(0);
+
+        public Fleet getFleet() { return fpga; }
+        public Dock getDebugInputDock() { return fpga.getShip("Debug",0).getDock("in"); }
+        public BitVector recvWord() {
+            if (isTerminated()) throw new RuntimeException("this fleet has been terminated");
+            try {
+                return queue.take();
+            } catch (InterruptedException e) { throw new RuntimeException(e); }
+        }
+        protected void _terminate() {
+            try {
+                PrintWriter pw = pwjtag;
+                if (pw==null) return;
+                synchronized(pw) {
+                    pw.close();
+                    pwjtag = null;
+                }
+            } catch (Exception e) { e.printStackTrace(); }
+        }
+
+        public void flush() {
+            try {
+                PrintWriter pw = pwjtag;
+                if (pw==null) return;
+                synchronized(pw) {
+                    pw.flush();
+                }
+            } catch (Exception e) { e.printStackTrace(); }
+        }
+
+        public void masterClear() {
+            try {
+                PrintWriter pw = pwjtag;
+                if (pw==null) return;
+                synchronized(pw) {
+                    pw.println("poke 0 "+((3<<6) | 27));
+                    pw.flush();
+                }
+
+                // it's important to acquire the semaphore first, then clear the queue
+                semaphore.acquire();
+                queue.clear();
+            } catch (Exception e) { throw new RuntimeException(); }
+        }
+
+
+        public JtagConnectedFpgaClient(Fpga fpga, String bitfile, Instruction[] instructions) throws Exception {
+            this.fpga = fpga;
+
+            ExecProcess jtag = new ExecProcess(new String[] { "ssh", "root@goliath.megacz.com", "cd ~/fleet; jtag" }, null);
+            jtag.redirectStderr(System.err);
+            jtag.start();
+
+            pwjtag = new PrintWriter(new OutputStreamWriter(jtag.getStdin()));
+            final BufferedReader pwjtagin = new BufferedReader(new InputStreamReader(jtag.getStdout()));
+            new Thread() {
+                public void run() {
+                    try {
+                        int i=0;
+                        long result = 0;
+                        while(true) {
+                            String sin = pwjtagin.readLine();
+                            if (sin==null) return;
+                            if (sin.indexOf("URJ_BUS_READ(")==-1) {
+                                if (sin.startsWith("Parsing  "))
+                                    System.err.print("\r"+sin+ANSI.clreol());
+                                else
+                                    System.err.println(sin);
+                                continue;
+                            }
+                            sin = sin.substring(sin.indexOf("URJ_BUS_READ("));
+                            sin = sin.substring(sin.indexOf(" = 0x"));
+                            sin = sin.substring(" = 0x".length());
+                            sin = sin.substring(0, sin.indexOf(' '));
+                            int val = Integer.parseInt(sin, 16);
+                            if (val < 256) continue;
+                            val = val & 0xff;
+                            //System.err.println("READ: 0x"+Integer.toString(val & 0xff, 16));
+                            if ((val & (3<<6)) == 0) {
+                                PrintWriter pw = pwjtag;
+                                if (pw==null) return;
+                                synchronized(pw) {
+                                    pw.println("poke 0 "+((1<<6) | 1));
+                                }
+                                peekSemaphore.release(3);
+                                result |= ((val & 0xffL) << (i * 6L));
+                                i++;
+                                if (i==8) {
+                                    BitVector bs = new BitVector(37);
+                                    for(int j=0; j<37; j++)
+                                        bs.set(j, ((result >> j) & 1L)!=0);
+                                    queue.put(bs);
+                                    i = 0;
+                                    result = 0;
+                                }
+                            } else {
+                                i = 0;
+                                PrintWriter pw = pwjtag;
+                                if (pw==null) return;
+                                synchronized(pw) {
+                                    pw.println("poke 0 "+((1<<6) | 15));
+                                    pw.flush();
+                                }
+                                peekSemaphore.release(3);
+                                semaphore.release();
+                            }
+
+                        }
+                    } catch (Exception e) { throw new RuntimeException(e); }
+                }
+            }.start();
+
+            PrintWriter pw = pwjtag;
+            //pw.println("cable Signalyzer");
+            pw.println("cable gnICE+");
+            pw.println("frequency 15000000");
+            
+            //pw.println("bsdl path misc/bsdl");
+            //pw.println("detect");
+            pw.println("addpart 10");
+            pw.println("addpart 8");
+            pw.println("addpart 8");
+            pw.println("addpart 16");
+            pw.println("addpart 16");
+            pw.println("part 1");
+            pw.println("instruction BYPASS");
+            pw.println("part 2");
+            pw.println("instruction BYPASS");
+            pw.println("part 3");
+            pw.println("instruction BYPASS");
+            pw.println("part 4");
+            pw.println("instruction BYPASS");
+            
+            pw.println("part 0");
+            pw.println("svf /root/fleet/build/ml509.small/main.svf stop progress");
+            pw.flush();
+            
+            //# fjmem commands
+            pw.println("register IR 10");
+            pw.println("initbus fjmem opcode=1111000010");
+            pw.flush();
+
+            System.err.println("done programming.");
+
+            // the thread that periodically sends a peek request
+            new Thread() {
+                public void run() {
+                    try {
+                        while(true) {
+                            peekSemaphore.tryAcquire(100, TimeUnit.MILLISECONDS);
+                            int avail = peekSemaphore.availablePermits();
+                            PrintWriter pw = pwjtag;
+                            if (pw==null) return;
+                            synchronized(pw) {
+                                pw.println("peek 0");
+                                if (avail==0) pw.flush();
+                            }
+                        }
+                    } catch (Exception e) { throw new RuntimeException(e); }
+                }
+            }.start();
+
+            masterClear();
+            if (instructions!=null) {
+                for(Instruction inst : instructions) sendInstruction(inst);
+                flush();
+            }
+        }
+
+        public void sendToken(Destination d) { sendWord(d, new BitVector(fpga.getWordWidth()), null, true); }
+        public void sendWord(Destination d, BitVector word) { sendWord(d, word, null, false); }
+        public void sendWord(Destination d, BitVector word, BitVector signal) { sendWord(d, word, signal, false); }
+        private void sendWord(Destination d, BitVector word, BitVector signal, boolean token) {
+            try {
+                Dock dispatchFrom = fpga.debugShip.getDock("in");
+                long out = 0;
+                out = fpga.PACKET_DATA.setval(out, word);
+                out = fpga.PACKET_TOKEN.setval(out, token ? 1 : 0);
+                out = signal==null ? fpga.PACKET_SIGNAL.setval(out, 0) : fpga.PACKET_SIGNAL.setval(out, signal);
+                out = fpga.PACKET_DEST.setval(out, ((FpgaPath)dispatchFrom.getPath(d, null)).toLong());
+                synchronized(this) {
+                    for(int i=9; i>=0; i--)
+                        synchronized(pwjtag) {
+                            pwjtag.println("poke 0 "+(BitManipulations.getIntField(i*6+5, i*6, out)&0xff));
+                            //pwjtag.flush();
+                        }
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        public void sendInstruction(Instruction inst) {
+            Dock dispatchFrom = fpga.debugShip.getDock("in");
+            sendWord(inst.dock.getInstructionDestination(),
+                     new BitVector(fpga.getWordWidth()).set(fpga.writeInstruction(inst, dispatchFrom)));
+        }
+
+        private static Move discard(Dock dock)           { return new Move(dock, IgnoreFlagD, false, null, false, true,  false, false, false, false); }
+        private static Move deliver(Dock dock)           { return new Move(dock, IgnoreFlagD, false, null, false, false, false, false, true,  false); }
+        private static Move wait(Dock dock)              { return new Move(dock, IgnoreFlagD, false, null, true,  false, false, false, false, false); }
+        private static Move sendto(Dock dock, Path path) { return new Move(dock, IgnoreFlagD, false, path, false, false, false, false, true,  false); }
+    }
+}
+