ship: BitFifo
 
 == Ports ===========================================================
-in:   inEnqueue
-in:   inEnqueueOp
-  constant rev:      .......................1.............
-  constant inv:      ........................1............
-  constant count:    .........................nnnnnn......
-  constant offset:   ...............................nnnnnn
-
-out:  outDequeue
-in:   inDequeueOp
+in:   in
+in:   inOp
+  constant lsbFirst: ....................................1
+  constant msbFirst: ....................................0
+  constant drop:     .............................uuuuuu..
+  constant take:     .......................uuuuuu........
+out:  out
+in:   outOp
+  constant lsbFirst:   ....................................1
+  constant msbFirst:   ....................................0
+  constant signExtend: ...................................1.
+  constant drop:       .............................uuuuuu..
+  constant take:       ......................0uuuuuu........
+  constant copy:       ......................1uuuuuu........
+
   
-== Sample Code ======================================================
+== TeX ==============================================================
 
+The BitFifo internally stores some number of bits in a fifo structure.
+Its capacity is guaranteed to be at least two full machine words or
+more.
 
-== Constants ========================================================
+Bits are enqueued by providing a word at the {\tt in} port and a count
+at the {\tt inOp} port (ports are named this way to take advantage of
+the switch fabric opcode mechanism).  The {\tt inOp} count may be
+positive, negative, or zero.
 
-== TeX ==============================================================
+If the {\tt inOp} count is positive, a word will be taken from the
+{\tt in} port and its {\tt count} least significant bits will be
+enqueued most-significant-bit first.
 
-\begin{verbatim}
-+-------------+   +---------------+   +------------+
-| inEnqueue   |-->|               |-->| outDequeue |
-+-------------+   |               |   +------------+
-                  |    BitFifo    |
-+-------------+   |               |   +-------------+
-| inEnqueueOp |-->|               |<--| inDequeueOp |
-+-------------+   +---------------+   +-------------+
-\end{verbatim}
+If the {\tt inOp} count is zero, a word will be {\it discarded} from
+the {\tt in} port and a duplicate copy of the bit at the {\it tail} of
+the fifo is enqueued.  If the fifo is empty, an undefined bit will be
+enqueued.  This mechanism is used for sign-extending words.
 
-\section*{inEnqueueOp}
-\setlength{\bitwidth}{6mm}
-{\tt\footnotesize
-\begin{bytefield}{14}
-  \bitheader[b]{0,5,6,11,12,13}\\
-  \bitbox{1}{Rev} 
-  \bitbox{1}{Inv} 
-  \bitbox{6}{Count} 
-  \bitbox{6}{Offset} 
-\end{bytefield}
-}
+If the {\tt inOp} count is negative, a word will be taken from the
+{\tt in} port and its {\tt |count|} most significant bits will be
+enqueued least-significant-bit first.
 
-\begin{itemize}
-   \item [\tt Rev]    ({\bf Reverse Before Enqueue})
-   \item [\tt Inv]    ({\bf Invert Count}) -- treat {\tt Count} as {\tt 37-Offset-Count}
-   \item [\tt Count]  ({\bf Count of Bits To Enqueue})
-   \item [\tt Offset] ({\bf Offset of Bits To Enqueue})
-\end{itemize}
-
-By default, bits are enqueued {\it most significant bit first} (bits
-in Sun byte order).  If {\tt Rev=1}, the bits are reversed before
-performing the directions below.
-
-If {\tt Inv=1}, then the {\tt Count} field is treated as if its value
-was actually {\tt 37-Offset-Count} for all directions below.
-
-
-
-\pagebreak
-
-\section*{inDequeueOp}
-\setlength{\bitwidth}{6mm}
-{\tt\scriptsize
-\begin{bytefield}{23}
-  \bitheader[b]{0,5,6,11-21,22}\\
-  \bitbox{2}{Until} 
-  \bitbox{1}{Sort} 
-  \bitbox{1}{Get} 
-  \bitbox{1}{Rev} 
-  \bitbox{1}{Inv} 
-  \bitbox{1}{Rst} 
-  \bitbox{2}{Left\\ Fill} 
-  \bitbox{2}{Right\\ Fill} 
-  \bitbox{6}{Count} 
-  \bitbox{6}{Offset} 
-\end{bytefield}
-}
+Whenever a full word is present in the fifo, it will be made available
+for dequeueing at the {\tt out} port.
 
-\begin{itemize}
-   \item [\tt Until]       ({\bf Shift until you see a (0, 1)})
-   \item [\tt Sort]        ({\bf Sort the Bits})
-   \item [\tt Get]         ({\bf Get the value of the counter})
-   \item [\tt Rev]         ({\bf Reverse Before Enqueue})
-   \item [\tt Inv]         ({\bf Invert Count}) -- treat {\tt Count} as {\tt 37-Offset-Count}
-   \item [\tt Rst]         ({\bf Reset Counter Before Operation})
-   \item [\tt Left Fill]   ({\bf Left Fill (0, 1, sign)})
-   \item [\tt Right Fill]  ({\bf Right Fill (0, 1, sign)})
-   \item [\tt Count]       ({\bf Count of Bits To Dequeue})
-   \item [\tt Offset]      ({\bf Offset of Bits To Dequeue})
-\end{itemize}
+\begin{verbatim}
+FIXMEs
+- previously I noted that it would be nice to be able to dequeue bits
+  without consuming them (ie copy-out).  What was this needed for?
+\end{verbatim}
 
 
 == Fleeterpreter ====================================================
   boolean hasSpace(int num) {
     return bits.length * 64 - numbits >= num;
   }
+  boolean peekTailBit() {
+    int entry = (((numbits-1) + start) / 64) % bits.length;
+    int off = ((numbits-1) + start) % 64;
+    int maxadd = 64 - off;
+    long mask = maxadd < 64 ? (-1L >>> maxadd) : 0L;
+    return (bits[entry] & ~mask) != 0;
+  }
   boolean add(long data, int num) {
     if (!hasSpace(num)) return false;
     int entry = ((numbits + start) / 64) % bits.length;
 private Packet selector;
 private static final int MAXBITS = 128;
 private static final int WORDSIZE = 37;
-private BitStorage bits = new BitStorage(MAXBITS);
+private Queue bits = new LinkedList<Boolean>();
+boolean last = false;
 
 // dummy routine used for Alu3 test -- FIXME later but keep this functionality somehow!
-public void service() {
-  if (!box_outDequeue.readyForDataFromShip() && !box_inEnqueue.dataReadyForShip()) return;
-  if (box_inEnqueue.dataReadyForShip() && bits.hasSpace(WORDSIZE)) {
-    long data = box_inEnqueue.removeDataForShip();
-    bits.add(data, WORDSIZE);
-    return;
-  }
-  if (box_outDequeue.readyForDataFromShip() && bits.size() > 0) {
-    long data = bits.get(1) == 0 ? 0L : 0x1FFFFFFFFFL;
-    box_outDequeue.addDataFromShip(data);
-    return;
-  }
+private void add(boolean bit) {
+  bits.add(bit);
+  last = bit;
 }
-
-/*
+private boolean get() {
+  return ((Boolean)bits.remove());
+}
+boolean haveBoxOutOp;
+long  boxOutOp;
 public void service() {
-  if (!box_outDequeue.readyForDataFromShip() && !box_inEnqueue.dataReadyForShip()) return;
-  if (box_inEnqueue.dataReadyForShip() && bits.hasSpace(WORDSIZE)) {
-    long data = box_inEnqueue.removeDataForShip();
-    bits.add(data, WORDSIZE);
+  if (box_inOp.dataReadyForShip() && box_in.dataReadyForShip()) {
+    long op    = box_inOp.removeDataForShip();
+    long data  = box_in.removeDataForShip();
+
+    boolean rev = (op & 1) != 0;
+    int drop    = (int)((op >> 2) & (~(0xffffffffL << 6)));
+    int take    = (int)((op >> 8) & (~(0xffffffffL << 6)));
+    if (take==0) { add(last); return; }
+
+    if (!rev)
+      for(long i=take-1-drop; i>=0; i--)
+        add( (data & (1L<<i)) != 0);
+    if (rev)
+      for(long i=WORDSIZE-take+drop; i<WORDSIZE; i++)
+        add( (data & (1L<<i)) != 0);
+    return;
   }
-  if (selector == null && !box_inEnqueueOp.dataReadyForShip()) return;
-  if (selector == null) selector = box_inEnqueueOp.removePacketForShip();
-
-  String port = selector.destination.getDestinationName();
-  long val = selector.value; // check if <= 37?
 
-  if (port.startsWith("takeInv") || port.startsWith("dropInv")) {
-    val = 37 - val;    
-  }
-  if (val < bits.size()) {
-    return;
+  if (!haveBoxOutOp && box_outOp.dataReadyForShip()) {
+     boxOutOp = box_outOp.removeDataForShip();
+     haveBoxOutOp = true;
   }
 
-  if (port.startsWith("take")) {
-    if (!box_outDequeue.readyForDataFromShip()) return;
-    long data = bits.get((int) val);
-    if (port.endsWith("FillOnes")) {
-      data |= (-1L << val);
-    } else if (port.endsWith("SignExtend")) {
-      data = (data << (64 - val)) >> (64 - val);
+  if (haveBoxOutOp && box_out.readyForDataFromShip()) {
+    long op = boxOutOp;
+    boolean rev  = (op & 1) != 0;
+    boolean sign = (op & 2) != 0;
+    boolean copy = (op & (1<<8)) != 0;
+    int drop     = (int)((op >> 2) & (~(0xffffffffL << 6)));
+    int take     = (int)((op >> 8) & (~(0xffffffffL << 6)));
+    if (bits.size() >= take+drop) {
+      // FIXME: copy
+      for(int i=0; i<drop; i++) get();
+      long ret = 0;
+      if (!rev) {
+        for(long i=take-1; i>=0; i--)
+          if (get()) ret |= 1L<<i;
+        if (sign && (ret & (1L<<(take-1)))!=0)
+          ret |= (0xffffffffffffffffL << take);
+      } else {
+        for(long i=WORDSIZE-take; i<WORDSIZE; i++)
+          if (get()) ret |= 1L<<i;
+        // FIXME: sign-extend!
+      }
+      box_out.addDataFromShip(ret);
+      haveBoxOutOp = false;
     }
-    box_outDequeue.addDataFromShip(data);
-    selector = null;
-    return;
-  } else {
-    bits.get((int) val);
-    selector = null;
-    return;
   }
 }
-*/
 
-== FleetSim ==============================================================
 
 == FPGA ==============================================================
   reg [73:0] bitstorage;
 
   always @(posedge clk) begin
     if (bitstorage_count == 0) begin
-      `onread(inEnqueue_r, inEnqueue_a)
-        bitstorage       <= inEnqueue_d;
+      `onread(in_r, in_a)
+        bitstorage       <= in_d;
         bitstorage_count <= 37;
-        outDequeue_d     <= (inEnqueue_d[0] ? 37'b1111111111111111111111111111111111111 : 0);
+        out_d            <= (in_d[0] ? 37'b1111111111111111111111111111111111111 : 0);
       end
     end else begin
-      `onwrite(outDequeue_r, outDequeue_a)
+      `onwrite(out_r, out_a)
         bitstorage_count <= bitstorage_count - 1;
-        outDequeue_d     <= (bitstorage[1] ? 37'b1111111111111111111111111111111111111 : 0);
+        out_d            <= (bitstorage[1] ? 37'b1111111111111111111111111111111111111 : 0);
         bitstorage       <= bitstorage >> 1;
       end
     end
 == Test ==============================================================
 
 // expected output
-#expect 137438953471
-#expect 137438953471
-#expect 0
-#expect 0
-#expect 0
-#expect 137438953471
-#expect 137438953471
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
-#expect 0
+#expect 1
+#expect 68719476736
+#expect 12
+#expect 13
 
 // ships required in order to run this code
 #ship debug        : Debug
 #ship bitfifo      : BitFifo
 
+BitFifo.outOp[take=37]: sendto bitfifo.outOp;
+bitfifo.outOp:          take; [*] deliver;
+
+// FIXME: test the drop capability
+
+// enqueue
+1:                      sendto bitfifo.in;
+BitFifo.inOp[take=37]:  sendto bitfifo.inOp;
+
+// enqueue reversed
+1:                          sendto bitfifo.in;
+BitFifo.inOp[take=37,lsbFirst]: sendto bitfifo.inOp;
+
+// test copy-last-bit
+0:                      sendto bitfifo.in;
+BitFifo.inOp[take=33]: sendto bitfifo.inOp;
+1:                      sendto bitfifo.in;
+BitFifo.inOp[take=1]: sendto bitfifo.inOp;
+1:                      sendto bitfifo.in;
+BitFifo.inOp[take=0]: sendto bitfifo.inOp;
+0:                      sendto bitfifo.in;
+BitFifo.inOp[take=1]: sendto bitfifo.inOp;
+1:                      sendto bitfifo.in;
+BitFifo.inOp[take=0]: sendto bitfifo.inOp;
+
+// ordering
+0:                      sendto bitfifo.in;
+BitFifo.inOp[take=33]: sendto bitfifo.inOp;
+13:                     sendto bitfifo.in;
+BitFifo.inOp[take=4]: sendto bitfifo.inOp;
+
+bitfifo.in:         [*] take, deliver;
+bitfifo.inOp:       [*] take, deliver;
+bitfifo.out:        [*] take, sendto debug.in;
 debug.in:           [*] take, deliver;
-99:                 sendto bitfifo.inEnqueue;
-bitfifo.inEnqueue:  take, deliver;
-bitfifo.outDequeue: [*] take, sendto debug.in;
+
 
 == Contributors =========================================================
 Amir Kamil <kamil@cs.berkeley.edu>