added toGet for MIFO

added toGet for MIFO

Change-Id: I3b0aac08338199ba8abab9f0511fe5fad05f8aae

// Copyright (c) 2014 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import Arith ::*;
import FIFOF ::*;
import GetPut::*;
import Pipe  ::*;
import MIMO  ::*; //LUInt

interface MIFO#(numeric type max_in, numeric type n_out, numeric type size, type t);
   method    Action                      enq(LUInt#(max_in) count, Vector#(max_in, t) data);
   method    Vector#(n_out, t)           first();
   method    Action                      deq();

   (* always_ready *)
   method    Bool                        enqReady();
   (* always_ready *)
   method    Bool                        deqReady();
endinterface

instance ToGet #(MIFO #(max_in, n_out, size, a), Vector#(n_out, a));
   function Get #(Vector#(n_out, a)) toGet (MIFO #(max_in, n_out, size, a) mifo);
      return (interface Get;
                 method ActionValue #(Vector#(n_out, a)) get ();
                    mifo.deq ();
                    return mifo.first ();
                 endmethod
              endinterface);
   endfunction
endinstance

module mkMIFO(MIFO#(max_in, n_out, size, t))
   provisos (Log#(max_in, max_in_sz),
	     Log#(n_out, n_out_sz),
	     Add#(n_out, a__, max_in),
	     Add#(1, b__, n_out),
	     Bits#(t, c__),
	     Bits#(Vector#(max_in, t), d__),
	     Add#(e__, max_in_sz, TLog#(TAdd#(max_in, 1))),
      Add#(f__, 2, max_in_sz)
      );
   FIFOF#(Vector#(max_in, t))     inFifo <- mkFIFOF();
   FIFOF#(UInt#(max_in_sz))      posFifo <- mkFIFOF();
   FIFOF#(LUInt#(max_in))    inCountFifo <- mkFIFOF();
   FIFOF#(Bit#(max_in))           weFifo <- mkFIFOF();
   Vector#(max_in, FIFOF#(t)) fifos      <- replicateM(mkSizedFIFOF(4));

   Reg#(UInt#(max_in_sz))            inPos <- mkReg(0);
   Reg#(UInt#(max_in_sz))            outPos <- mkReg(0);

   LUInt#(max_in) i_max_in = fromInteger(valueOf(max_in));

   let verbose = False;

   function a fifoFirst(FIFOF#(a) fifo); if (fifo.notEmpty()) return fifo.first(); else return ?; endfunction
   function Bool fifoNotEmpty(FIFOF#(a) fifo); return fifo.notEmpty(); endfunction
   function Bool fifoNotFull(FIFOF#(a) fifo); return fifo.notFull(); endfunction

   FIFOF#(Bool) checkInFifo <- mkFIFOF();
   rule checkin if (verbose);
      let v <- toGet(checkInFifo).get();
      $display("checkIn: inPos=%d outPos=%d notEmpties: %h notFulls: %h values: %h",
	       inPos, outPos, map(fifoNotEmpty, fifos), map(fifoNotFull, fifos), map(fifoFirst, fifos));
   endrule

   rule tofifos;
      let values = inFifo.first;
      let count  = inCountFifo.first;
      let pos    = posFifo.first;
      let we     = weFifo.first;

      Bool ready = True;
      // for (Integer i = 0; i < valueOf(max_in); i = i+1) begin
      // 	 if (we[i] == 1)
      // 	    ready = ready && fifos[i].notFull();
      // end
      if (ready) begin
	 for (Integer i = 0; i < valueOf(max_in); i = i+1) begin
	    if (we[i] == 1)
	       fifos[i].enq(values[i]);
	 end
	 inFifo.deq();
	 inCountFifo.deq();
	 weFifo.deq();
	 posFifo.deq();

	 if (verbose) begin
	    $display("tofifos: pos=%d count=%d we=%h", pos, count, we, " values: %h notFull: %h", values, map(fifoNotFull, fifos));
	    checkInFifo.enq(True);
	 end
      end
   endrule

   function Bool deqReadyInternal();
      LUInt#(max_in) rot = i_max_in - extend(outPos);
      Vector#(n_out, Bool) notEmpties = take(rotateBy(map(fifoNotEmpty, fifos), truncate(rot)));
      return fold(booland, notEmpties);
   endfunction

   FIFOF#(Bool) checkFifo <- mkFIFOF();
   rule check if (verbose);
      let v <- toGet(checkFifo).get();
      LUInt#(max_in) rot = i_max_in - extend(outPos);
      Vector#(max_in, Bool) allNotEmpties = map(fifoNotEmpty, fifos);
      Vector#(max_in, Bool) notEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
      Vector#(4, Bool) testv = replicate(False);
      testv[outPos] = True;
      UInt#(2) testpos = 3 - truncate(outPos);
      Vector#(4, Bool) rotatedTestv = rotateBy(testv, 1);
      if (verbose)
      $display("check outPos: ", outPos, " notEmpty: ", fifos[outPos].notEmpty(),
	 " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
   endrule

   method    Action                      enq(LUInt#(max_in) count, Vector#(max_in, t) data);
      function Bool lessThanCount(Integer i); return fromInteger(i) < count; endfunction
      Vector#(max_in, Bool) we = genWith(lessThanCount);
      inFifo.enq(rotateBy(data, inPos));
      inCountFifo.enq(count);
      weFifo.enq(pack(rotateBy(we, inPos)));
      posFifo.enq(inPos);
      inPos <= truncate((extend(inPos) + count) % i_max_in);

      if (verbose) $display("enq: inPos=%d we=%h", inPos, we);
   endmethod

   method    Vector#(n_out, t)           first if (deqReadyInternal());
      function t firstN(Integer i);
	 return fifos[(extend(outPos) + fromInteger(i)) % i_max_in].first;
      endfunction
      return genWith(firstN);
   endmethod

   method    Action                      deq() if (deqReadyInternal());
      function t firstN(Integer i);
	 return fifos[(extend(outPos) + fromInteger(i)) % i_max_in].first;
      endfunction
      for (Integer i = 0; i < valueOf(n_out); i = i+1)
	 fifos[(extend(outPos) + fromInteger(i)) % i_max_in].deq();
      UInt#(max_in_sz) nextOutPos = truncate((extend(outPos) + fromInteger(valueOf(n_out))) % i_max_in);
      outPos <= nextOutPos;

      if (verbose) begin
	 LUInt#(max_in) rot = i_max_in - extend(outPos);
	 Vector#(n_out, t) v = genWith(firstN);
	 Vector#(max_in, Bool) allNotEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
	 Vector#(n_out, Bool) notEmpties = take(map(fifoNotEmpty, rotateBy(fifos, truncate(rot))));
	 $display("first: ", v, " outPos: ", outPos, " nextOutPos: ", nextOutPos, " nextNotEmpty: ", fifos[nextOutPos].notEmpty(),
	    " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
	 checkFifo.enq(True);
      end
   endmethod

   method    Bool                        enqReady = inFifo.notFull;

   method    Bool                        deqReady = deqReadyInternal;

endmodule

interface FIMO#(numeric type n_in, numeric type max_out, numeric type size, type t);
   interface PipeIn#(Vector#(n_in, t)) in;
   interface Vector#(TAdd#(max_out,1), PipeOut#(Vector#(max_out, t))) out;
endinterface

module mkFIMO(FIMO#(n_in, max_out, size, t))
   provisos (Log#(n_in, n_in_sz),
	     Log#(max_out, max_out_sz),
	     Add#(n_in, a__, max_out),
	     Add#(1, b__, max_out),
	     Bits#(t, c__),
	     Add#(d__, max_out_sz, TLog#(TAdd#(max_out, 1)))
      );
   FIFOF#(Vector#(max_out, t))     inFifo <- mkFIFOF();
   FIFOF#(UInt#(max_out_sz))      posFifo <- mkFIFOF();
   FIFOF#(Bit#(max_out))           weFifo <- mkFIFOF();
   Vector#(max_out, FIFOF#(t))      fifos <- replicateM(mkFIFOF());

   Reg#(UInt#(max_out_sz))            inPos <- mkReg(0);
   Reg#(UInt#(max_out_sz))            outPos <- mkReg(0);

   LUInt#(max_out) i_n_in = fromInteger(valueOf(n_in));
   LUInt#(max_out) i_max_out = fromInteger(valueOf(max_out));

   let verbose = False;

   function a fifoFirst(FIFOF#(a) fifo); if (fifo.notEmpty()) return fifo.first(); else return ?; endfunction
   function Bool fifoNotEmpty(FIFOF#(a) fifo); return fifo.notEmpty(); endfunction
   function Bool fifoNotFull(FIFOF#(a) fifo); return fifo.notFull(); endfunction

   FIFOF#(Bool) checkInFifo <- mkFIFOF();
   rule checkin if (verbose);
      let v <- toGet(checkInFifo).get();
      $display("checkIn: inPos=%d outPos=%d notEmpties: %h notFulls: %h values: %h",
	       inPos, outPos, map(fifoNotEmpty, fifos), map(fifoNotFull, fifos), map(fifoFirst, fifos));
   endrule

   rule tofifos;
      let values = inFifo.first;
      let pos    = posFifo.first;
      let we     = weFifo.first;

      Bool ready = True;
      // for (Integer i = 0; i < valueOf(max_out); i = i+1) begin
      // 	 if (we[i] == 1)
      // 	    ready = ready && fifos[i].notFull();
      // end
      $display("tofifos: we=%h", we);
      if (ready) begin
	 for (Integer i = 0; i < valueOf(max_out); i = i+1) begin
	    if (we[i] == 1)
	       fifos[i].enq(values[i]);
	 end
	 inFifo.deq();
	 weFifo.deq();
	 posFifo.deq();

	 if (verbose) begin
	    $display("tofifos: pos=%d we=%h", pos, we, " values: %h notFull: %h", values, map(fifoNotFull, fifos));
	    checkInFifo.enq(True);
	 end
      end
   endrule

   function Bool deqReadyInternal(Integer n_out);
      LUInt#(max_out) rot = i_max_out - extend(outPos);
      Vector#(max_out, Bool) notEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));

      function Bool n_notEmpty(Integer i); if (i < n_out) return notEmpties[i]; else return True; endfunction
      Vector#(max_out, Bool) n_notEmpties = genWith(n_notEmpty);

      return fold(booland, n_notEmpties);
   endfunction

   FIFOF#(Bool) checkFifo <- mkFIFOF();
   rule check if (verbose);
      let v <- toGet(checkFifo).get();
      LUInt#(max_out) rot = i_max_out - extend(outPos);
      Vector#(max_out, Bool) allNotEmpties = map(fifoNotEmpty, fifos);
      Vector#(max_out, Bool) notEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
      if (verbose)
      $display("check outPos: ", outPos, " notEmpty: ", fifos[outPos].notEmpty(),
	 " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
   endrule

   function PipeIn#(Vector#(n_in, t)) genInPipe(Integer i);
      return (interface PipeIn#(Vector#(n_in, t))
		 method Action enq(Vector#(n_in, t) data);
		    function Bool lessThanCount(Integer i); return fromInteger(i) < i_n_in; endfunction
		    Vector#(max_out, Bool) we = genWith(lessThanCount);
		    Vector#(max_out, t) wdata = append(data, replicate(?));
		    inFifo.enq(rotateBy(wdata, inPos));
		    posFifo.enq(inPos);
		    weFifo.enq(pack(rotateBy(we, inPos)));
		    inPos <= truncate((extend(inPos) + extend(i_n_in)) % i_max_out);

		    if (verbose) begin
		       $display("enq: inPos=%d we=%h", inPos, we);
		    end
		 endmethod
		 method notFull = inFifo.notFull;
	      endinterface);
   endfunction

   function PipeOut#(Vector#(max_out, t)) genOutPipe(Integer n_out);
      function t firstN(Integer i);
	 if (i < n_out)
	    return fifos[(extend(outPos) + fromInteger(i)) % i_max_out].first;
	 else
	    return ?;
      endfunction

      PipeOut#(Vector#(max_out, t)) pipeOut =
        (interface PipeOut#(Vector#(max_out, t))
	    method    Vector#(max_out, t)           first if (deqReadyInternal(n_out));
	       return genWith(firstN);
	    endmethod

	    method    Action                      deq() if (deqReadyInternal(n_out));
	       for (Integer i = 0; i < n_out; i = i+1)
		  fifos[(extend(outPos) + fromInteger(i)) % i_max_out].deq();
	       UInt#(max_out_sz) nextOutPos = truncate((extend(outPos) + fromInteger(valueOf(max_out))) % i_max_out);
	       outPos <= nextOutPos;

	       if (verbose) begin
		  LUInt#(max_out) rot = i_max_out - extend(outPos);
		  Vector#(max_out, t) v = genWith(firstN);
		  Vector#(max_out, Bool) allNotEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
		  Vector#(max_out, Bool) notEmpties = map(fifoNotEmpty, rotateBy(fifos, truncate(rot)));
		  $display("first: ", v, " outPos: ", outPos, " nextOutPos: ", nextOutPos, " nextNotEmpty: ", fifos[nextOutPos].notEmpty(),
		     " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
		  checkFifo.enq(True);
	       end
	    endmethod

	    method notEmpty  = deqReadyInternal(n_out);
	 endinterface);
      return pipeOut;
   endfunction

   interface Vector in = genInPipe(0);
   interface Vector out = genWith(genOutPipe);
endmodule

// Copyright (c) 2014 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import Arith ::*;
import FIFOF ::*;
import GetPut::*;
import Pipe  ::*;
import MIMO  ::*; //LUInt

interface MIFO#(numeric type max_in, numeric type n_out, numeric type size, type t);
   method    Action                      enq(LUInt#(max_in) count, Vector#(max_in, t) data);
   method    Vector#(n_out, t)           first();
   method    Action                      deq();

   (* always_ready *)
   method    Bool                        enqReady();
   (* always_ready *)
   method    Bool                        deqReady();
endinterface

module mkMIFO(MIFO#(max_in, n_out, size, t))
   provisos (Log#(max_in, max_in_sz),
	     Log#(n_out, n_out_sz),
	     Add#(n_out, a__, max_in),
	     Add#(1, b__, n_out),
	     Bits#(t, c__),
	     Bits#(Vector#(max_in, t), d__),
	     Add#(e__, max_in_sz, TLog#(TAdd#(max_in, 1))),
      Add#(f__, 2, max_in_sz)
      );
   FIFOF#(Vector#(max_in, t))     inFifo <- mkFIFOF();
   FIFOF#(UInt#(max_in_sz))      posFifo <- mkFIFOF();
   FIFOF#(LUInt#(max_in))    inCountFifo <- mkFIFOF();
   FIFOF#(Bit#(max_in))           weFifo <- mkFIFOF();
   Vector#(max_in, FIFOF#(t)) fifos      <- replicateM(mkSizedFIFOF(4));

   Reg#(UInt#(max_in_sz))            inPos <- mkReg(0);
   Reg#(UInt#(max_in_sz))            outPos <- mkReg(0);

   LUInt#(max_in) i_max_in = fromInteger(valueOf(max_in));

   let verbose = False;

   function a fifoFirst(FIFOF#(a) fifo); if (fifo.notEmpty()) return fifo.first(); else return ?; endfunction
   function Bool fifoNotEmpty(FIFOF#(a) fifo); return fifo.notEmpty(); endfunction
   function Bool fifoNotFull(FIFOF#(a) fifo); return fifo.notFull(); endfunction

   FIFOF#(Bool) checkInFifo <- mkFIFOF();
   rule checkin if (verbose);
      let v <- toGet(checkInFifo).get();
      $display("checkIn: inPos=%d outPos=%d notEmpties: %h notFulls: %h values: %h",
	       inPos, outPos, map(fifoNotEmpty, fifos), map(fifoNotFull, fifos), map(fifoFirst, fifos));
   endrule

   rule tofifos;
      let values = inFifo.first;
      let count  = inCountFifo.first;
      let pos    = posFifo.first;
      let we     = weFifo.first;

      Bool ready = True;
      // for (Integer i = 0; i < valueOf(max_in); i = i+1) begin
      // 	 if (we[i] == 1)
      // 	    ready = ready && fifos[i].notFull();
      // end
      if (ready) begin
	 for (Integer i = 0; i < valueOf(max_in); i = i+1) begin
	    if (we[i] == 1)
	       fifos[i].enq(values[i]);
	 end
	 inFifo.deq();
	 inCountFifo.deq();
	 weFifo.deq();
	 posFifo.deq();

	 if (verbose) begin
	    $display("tofifos: pos=%d count=%d we=%h", pos, count, we, " values: %h notFull: %h", values, map(fifoNotFull, fifos));
	    checkInFifo.enq(True);
	 end
      end
   endrule

   function Bool deqReadyInternal();
      LUInt#(max_in) rot = i_max_in - extend(outPos);
      Vector#(n_out, Bool) notEmpties = take(rotateBy(map(fifoNotEmpty, fifos), truncate(rot)));
      return fold(booland, notEmpties);
   endfunction

   FIFOF#(Bool) checkFifo <- mkFIFOF();
   rule check if (verbose);
      let v <- toGet(checkFifo).get();
      LUInt#(max_in) rot = i_max_in - extend(outPos);
      Vector#(max_in, Bool) allNotEmpties = map(fifoNotEmpty, fifos);
      Vector#(max_in, Bool) notEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
      Vector#(4, Bool) testv = replicate(False);
      testv[outPos] = True;
      UInt#(2) testpos = 3 - truncate(outPos);
      Vector#(4, Bool) rotatedTestv = rotateBy(testv, 1);
      if (verbose)
      $display("check outPos: ", outPos, " notEmpty: ", fifos[outPos].notEmpty(),
	 " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
   endrule

   method    Action                      enq(LUInt#(max_in) count, Vector#(max_in, t) data);
      function Bool lessThanCount(Integer i); return fromInteger(i) < count; endfunction
      Vector#(max_in, Bool) we = genWith(lessThanCount);
      inFifo.enq(rotateBy(data, inPos));
      inCountFifo.enq(count);
      weFifo.enq(pack(rotateBy(we, inPos)));
      posFifo.enq(inPos);
      inPos <= truncate((extend(inPos) + count) % i_max_in);

      if (verbose) $display("enq: inPos=%d we=%h", inPos, we);
   endmethod

   method    Vector#(n_out, t)           first if (deqReadyInternal());
      function t firstN(Integer i);
	 return fifos[(extend(outPos) + fromInteger(i)) % i_max_in].first;
      endfunction
      return genWith(firstN);
   endmethod

   method    Action                      deq() if (deqReadyInternal());
      function t firstN(Integer i);
	 return fifos[(extend(outPos) + fromInteger(i)) % i_max_in].first;
      endfunction
      for (Integer i = 0; i < valueOf(n_out); i = i+1)
	 fifos[(extend(outPos) + fromInteger(i)) % i_max_in].deq();
      UInt#(max_in_sz) nextOutPos = truncate((extend(outPos) + fromInteger(valueOf(n_out))) % i_max_in);
      outPos <= nextOutPos;

      if (verbose) begin
	 LUInt#(max_in) rot = i_max_in - extend(outPos);
	 Vector#(n_out, t) v = genWith(firstN);
	 Vector#(max_in, Bool) allNotEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
	 Vector#(n_out, Bool) notEmpties = take(map(fifoNotEmpty, rotateBy(fifos, truncate(rot))));
	 $display("first: ", v, " outPos: ", outPos, " nextOutPos: ", nextOutPos, " nextNotEmpty: ", fifos[nextOutPos].notEmpty(),
	    " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
	 checkFifo.enq(True);
      end
   endmethod

   method    Bool                        enqReady = inFifo.notFull;

   method    Bool                        deqReady = deqReadyInternal;

endmodule

interface FIMO#(numeric type n_in, numeric type max_out, numeric type size, type t);
   interface PipeIn#(Vector#(n_in, t)) in;
   interface Vector#(TAdd#(max_out,1), PipeOut#(Vector#(max_out, t))) out;
endinterface

module mkFIMO(FIMO#(n_in, max_out, size, t))
   provisos (Log#(n_in, n_in_sz),
	     Log#(max_out, max_out_sz),
	     Add#(n_in, a__, max_out),
	     Add#(1, b__, max_out),
	     Bits#(t, c__),
	     Add#(d__, max_out_sz, TLog#(TAdd#(max_out, 1)))
      );
   FIFOF#(Vector#(max_out, t))     inFifo <- mkFIFOF();
   FIFOF#(UInt#(max_out_sz))      posFifo <- mkFIFOF();
   FIFOF#(Bit#(max_out))           weFifo <- mkFIFOF();
   Vector#(max_out, FIFOF#(t))      fifos <- replicateM(mkFIFOF());

   Reg#(UInt#(max_out_sz))            inPos <- mkReg(0);
   Reg#(UInt#(max_out_sz))            outPos <- mkReg(0);

   LUInt#(max_out) i_n_in = fromInteger(valueOf(n_in));
   LUInt#(max_out) i_max_out = fromInteger(valueOf(max_out));

   let verbose = False;

   function a fifoFirst(FIFOF#(a) fifo); if (fifo.notEmpty()) return fifo.first(); else return ?; endfunction
   function Bool fifoNotEmpty(FIFOF#(a) fifo); return fifo.notEmpty(); endfunction
   function Bool fifoNotFull(FIFOF#(a) fifo); return fifo.notFull(); endfunction

   FIFOF#(Bool) checkInFifo <- mkFIFOF();
   rule checkin if (verbose);
      let v <- toGet(checkInFifo).get();
      $display("checkIn: inPos=%d outPos=%d notEmpties: %h notFulls: %h values: %h",
	       inPos, outPos, map(fifoNotEmpty, fifos), map(fifoNotFull, fifos), map(fifoFirst, fifos));
   endrule

   rule tofifos;
      let values = inFifo.first;
      let pos    = posFifo.first;
      let we     = weFifo.first;

      Bool ready = True;
      // for (Integer i = 0; i < valueOf(max_out); i = i+1) begin
      // 	 if (we[i] == 1)
      // 	    ready = ready && fifos[i].notFull();
      // end
      $display("tofifos: we=%h", we);
      if (ready) begin
	 for (Integer i = 0; i < valueOf(max_out); i = i+1) begin
	    if (we[i] == 1)
	       fifos[i].enq(values[i]);
	 end
	 inFifo.deq();
	 weFifo.deq();
	 posFifo.deq();

	 if (verbose) begin
	    $display("tofifos: pos=%d we=%h", pos, we, " values: %h notFull: %h", values, map(fifoNotFull, fifos));
	    checkInFifo.enq(True);
	 end
      end
   endrule

   function Bool deqReadyInternal(Integer n_out);
      LUInt#(max_out) rot = i_max_out - extend(outPos);
      Vector#(max_out, Bool) notEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));

      function Bool n_notEmpty(Integer i); if (i < n_out) return notEmpties[i]; else return True; endfunction
      Vector#(max_out, Bool) n_notEmpties = genWith(n_notEmpty);

      return fold(booland, n_notEmpties);
   endfunction

   FIFOF#(Bool) checkFifo <- mkFIFOF();
   rule check if (verbose);
      let v <- toGet(checkFifo).get();
      LUInt#(max_out) rot = i_max_out - extend(outPos);
      Vector#(max_out, Bool) allNotEmpties = map(fifoNotEmpty, fifos);
      Vector#(max_out, Bool) notEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
      if (verbose)
      $display("check outPos: ", outPos, " notEmpty: ", fifos[outPos].notEmpty(),
	 " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
   endrule

   function PipeIn#(Vector#(n_in, t)) genInPipe(Integer i);
      return (interface PipeIn#(Vector#(n_in, t))
		 method Action enq(Vector#(n_in, t) data);
		    function Bool lessThanCount(Integer i); return fromInteger(i) < i_n_in; endfunction
		    Vector#(max_out, Bool) we = genWith(lessThanCount);
		    Vector#(max_out, t) wdata = append(data, replicate(?));
		    inFifo.enq(rotateBy(wdata, inPos));
		    posFifo.enq(inPos);
		    weFifo.enq(pack(rotateBy(we, inPos)));
		    inPos <= truncate((extend(inPos) + extend(i_n_in)) % i_max_out);

		    if (verbose) begin
		       $display("enq: inPos=%d we=%h", inPos, we);
		    end
		 endmethod
		 method notFull = inFifo.notFull;
	      endinterface);
   endfunction

   function PipeOut#(Vector#(max_out, t)) genOutPipe(Integer n_out);
      function t firstN(Integer i);
	 if (i < n_out)
	    return fifos[(extend(outPos) + fromInteger(i)) % i_max_out].first;
	 else
	    return ?;
      endfunction

      PipeOut#(Vector#(max_out, t)) pipeOut =
        (interface PipeOut#(Vector#(max_out, t))
	    method    Vector#(max_out, t)           first if (deqReadyInternal(n_out));
	       return genWith(firstN);
	    endmethod

	    method    Action                      deq() if (deqReadyInternal(n_out));
	       for (Integer i = 0; i < n_out; i = i+1)
		  fifos[(extend(outPos) + fromInteger(i)) % i_max_out].deq();
	       UInt#(max_out_sz) nextOutPos = truncate((extend(outPos) + fromInteger(valueOf(max_out))) % i_max_out);
	       outPos <= nextOutPos;

	       if (verbose) begin
		  LUInt#(max_out) rot = i_max_out - extend(outPos);
		  Vector#(max_out, t) v = genWith(firstN);
		  Vector#(max_out, Bool) allNotEmpties = rotateBy(map(fifoNotEmpty, fifos), truncate(rot));
		  Vector#(max_out, Bool) notEmpties = map(fifoNotEmpty, rotateBy(fifos, truncate(rot)));
		  $display("first: ", v, " outPos: ", outPos, " nextOutPos: ", nextOutPos, " nextNotEmpty: ", fifos[nextOutPos].notEmpty(),
		     " notEmpties: ", notEmpties, " allNotEmpties: %h", allNotEmpties);
		  checkFifo.enq(True);
	       end
	    endmethod

	    method notEmpty  = deqReadyInternal(n_out);
	 endinterface);
      return pipeOut;
   endfunction

   interface Vector in = genInPipe(0);
   interface Vector out = genWith(genOutPipe);
endmodule


code is drastically simpler

code is drastically simpler

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;
import Connectable::*;

// portz libraries
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import PortalMemory::*;
import MemServer::*;
import PortalMemory::*;
import Dma::*;
import DmaUtils::*;
import RbmTypes::*;

// generated by tool
import DmaConfigWrapper::*;
import DmaIndicationProxy::*;
import MmIndicationProxy::*;
import MmRequestWrapper::*;
import TimerIndicationProxy::*;
import TimerRequestWrapper::*;

// defined by user
import Matrix::*;

module [Module] mkPortalTop(PortalTop#(addrWidth,TMul#(32,N),Empty,1))
   provisos (Add#(a__, addrWidth, 40),
	     Add#(a__, b__, 40),
	     Add#(addrWidth, c__, 52),
	     Add#(addrWidth, d__, 64),
	     Add#(e__, f__, 40),
	     Add#(f__, 12, b__),
	     Add#(b__, g__, 44)
	     );

   DmaIndicationProxy dmaIndicationProxy <- mkDmaIndicationProxy(DmaIndicationPortal);

   MmIndicationProxy mmIndicationProxy <- mkMmIndicationProxy(MmIndicationPortal);
   TimerIndicationProxy timerIndicationProxy <- mkTimerIndicationProxy(TimerIndicationPortal);
   Mm#(N) mm <- mkMm(mmIndicationProxy.ifc, timerIndicationProxy.ifc);
   MmRequestWrapper mmRequestWrapper <- mkMmRequestWrapper(MmRequestPortal,mm.mmRequest);
   TimerRequestWrapper timerRequestWrapper <- mkTimerRequestWrapper(TimerRequestPortal,mm.timerRequest);

   Vector#(TAdd#(K,J) ,DmaReadBuffer#(TMul#(32,N),16)) read_buffers <- replicateM(mkDmaReadBuffer);
   zipWithM(mkConnection, mm.readClients, map(ors, read_buffers));
   let readClients = map(orc, read_buffers);

   Vector#(1, DmaWriteBuffer#(TMul#(32,N),16)) write_buffers <- replicateM(mkDmaWriteBuffer);
   zipWithM(mkConnection, mm.writeClients, map(ows,write_buffers));
   let writeClients = map(owc, write_buffers);

   MemServer#(addrWidth, TMul#(32,N), 1) dma <- mkMemServer(dmaIndicationProxy.ifc, readClients, writeClients);
   DmaConfigWrapper dmaConfigWrapper <- mkDmaConfigWrapper(DmaConfigPortal,dma.request);

   Vector#(6,StdPortal) portals;
   portals[0] = mmRequestWrapper.portalIfc;
   portals[1] = mmIndicationProxy.portalIfc;
   portals[2] = dmaConfigWrapper.portalIfc;
   portals[3] = dmaIndicationProxy.portalIfc;
   portals[4] = timerRequestWrapper.portalIfc;
   portals[5] = timerIndicationProxy.portalIfc;
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = dma.masters;

endmodule : mkPortalTop

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;
import Connectable::*;

// portz libraries
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import PortalMemory::*;
import MemServer::*;
import PortalMemory::*;
import Dma::*;
import DmaUtils::*;
import RbmTypes::*;

// generated by tool
import DmaConfigWrapper::*;
import DmaIndicationProxy::*;
import MmIndicationProxy::*;
import MmRequestWrapper::*;
import TimerIndicationProxy::*;
import TimerRequestWrapper::*;

// defined by user
import Matrix::*;

module [Module] mkPortalTop(PortalTop#(addrWidth,TMul#(32,N),Empty,1))
   provisos (Add#(a__, addrWidth, 40),
	     Add#(a__, b__, 40),
	     Add#(addrWidth, c__, 52),
	     Add#(addrWidth, d__, 64),
	     Add#(e__, f__, 40),
	     Add#(f__, 12, b__),
	     Add#(b__, g__, 44)
	     );

   DmaIndicationProxy dmaIndicationProxy <- mkDmaIndicationProxy(DmaIndicationPortal);

   MmIndicationProxy mmIndicationProxy <- mkMmIndicationProxy(MmIndicationPortal);
   TimerIndicationProxy timerIndicationProxy <- mkTimerIndicationProxy(TimerIndicationPortal);
   Mm#(N) mm <- mkMm(mmIndicationProxy.ifc, timerIndicationProxy.ifc);
   MmRequestWrapper mmRequestWrapper <- mkMmRequestWrapper(MmRequestPortal,mm.mmRequest);
   TimerRequestWrapper timerRequestWrapper <- mkTimerRequestWrapper(TimerRequestPortal,mm.timerRequest);

   let readClients = mm.readClients;
   Bool buffered = True;
   if (buffered) begin
      function Module#(DmaReadBuffer#(TMul#(N,32), 16)) mkBuffer(a x);
	 return mkDmaReadBuffer();
      endfunction
      let buffers <- mapM(mkBuffer, mm.readClients);

      function Module#(Empty) connect(Tuple2#(DmaReadBuffer#(dsz, burstlen), ObjectReadClient#(dsz)) tpl);
	 return mkConnection(tpl_2(tpl), tpl_1(tpl).dmaServer);
      endfunction
      let connections <- mapM(connect, zip(buffers, mm.readClients));

      function ObjectReadClient#(dsz) dmaClient(DmaReadBuffer#(dsz, burstlen) b);
	 return b.dmaClient;
      endfunction
      readClients = map(dmaClient, buffers);
   end
   else begin
      readClients = mm.readClients;
   end

   let writeClients = mm.writeClients;
   if (buffered) begin
      function Module#(DmaWriteBuffer#(TMul#(N,32), 16)) mkBuffer(a x);
	 return mkDmaWriteBuffer();
      endfunction
      let buffers <- mapM(mkBuffer, mm.writeClients);

      function Module#(Empty) connect(Tuple2#(DmaWriteBuffer#(dsz, burstlen), ObjectWriteClient#(dsz)) tpl);
	 return mkConnection(tpl_2(tpl), tpl_1(tpl).dmaServer);
      endfunction
      let connections <- mapM(connect, zip(buffers, mm.writeClients));

      function ObjectWriteClient#(dsz) dmaClient(DmaWriteBuffer#(dsz, burstlen) b);
	 return b.dmaClient;
      endfunction
      writeClients = map(dmaClient, buffers);
   end
   else begin
      writeClients = mm.writeClients;
   end

   MemServer#(addrWidth, TMul#(32,N), 1) dma <- mkMemServer(dmaIndicationProxy.ifc, readClients, writeClients);

   DmaConfigWrapper dmaConfigWrapper <- mkDmaConfigWrapper(DmaConfigPortal,dma.request);

   Vector#(6,StdPortal) portals;
   portals[0] = mmRequestWrapper.portalIfc;
   portals[1] = mmIndicationProxy.portalIfc;
   portals[2] = dmaConfigWrapper.portalIfc;
   portals[3] = dmaIndicationProxy.portalIfc;
   portals[4] = timerRequestWrapper.portalIfc;
   portals[5] = timerIndicationProxy.portalIfc;

   StdDirectory dir <- mkStdDirectory(portals);

   // when constructing ctrl and interrupt muxes, directories must be the first argument
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = dma.masters;

endmodule : mkPortalTop


make sure all data is received before indicating done

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;

import Pipe::*;
import MemTypes::*;
import MemreadEngine::*;
import Pipe::*;

interface RtestRequest;
   method Action startRead(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
endinterface

interface Rtest;
   interface RtestRequest request;
   interface MemReadClient#(64) dmaClient;
endinterface

interface RtestIndication;
   method Action readDone(Bit#(32) mismatchCount);
endinterface

module mkRtest#(RtestIndication indication) (Rtest);

   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))       numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   FIFO#(void)                cf <- mkSizedFIFO(1);
   Reg#(Bit#(32))  itersToFinish <- mkReg(0);
   Reg#(Bit#(32))   itersToStart <- mkReg(0);
   Reg#(Bit#(32))        wordsRead <- mkReg(0);
   Reg#(Bit#(32)) mismatchCounts <- mkReg(0);
   MemreadEngine#(64,1,1)        re <- mkMemreadEngine;
   Bit#(32)             numBytes = extend(numWords)*4;
   FIFO#(Bit#(32)) checkDoneFifo <- mkFIFO();

   rule start (itersToStart > 0);
      re.readServers[0].request.put(MemengineCmd{sglId:pointer, base:0, len:numBytes, burstLen:burstLenBytes});
      itersToStart <= itersToStart-1;
   endrule

   rule check;
      let v <- toGet(re.dataPipes[0]).get;
      let expectedV = {wordsRead+1,wordsRead};
      let misMatch = v != expectedV;
      mismatchCounts <= mismatchCounts + (misMatch ? 1 : 0);
      // $display("check v=%h expected=%h mismatch=%d", v, expectedV, misMatch);
      let new_wordsRead = wordsRead+(64/32);
      if (new_wordsRead >= truncate(numBytes/4)) begin
	 new_wordsRead = 0;
	 checkDoneFifo.enq(mismatchCounts);
      end
      wordsRead <= new_wordsRead;
   endrule

   rule finish if (itersToFinish > 0);
      let mc <- toGet(checkDoneFifo).get();
      let rv <- re.readServers[0].response.get;
      if (itersToFinish == 1) begin
	 cf.deq;
	 indication.readDone(mismatchCounts);
      end
      itersToFinish <= itersToFinish - 1;
   endrule

   interface dmaClient = re.dmaClient;
   interface RtestRequest request;
      method Action startRead(Bit#(32) rp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic) if (itersToStart == 0 && itersToFinish == 0);
	 pointer <= rp;
	 cf.enq(?);
	 numWords  <= nw;
	 burstLenBytes  <= truncate(bl*4);
	 itersToFinish <= ic;
	 itersToStart <= ic;
	 mismatchCounts <= 0;
	 wordsRead <= 0;
      endmethod
   endinterface
endmodule

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;

import Pipe::*;
import MemTypes::*;
import MemreadEngine::*;
import Pipe::*;

interface RtestRequest;
   method Action startRead(Bit#(32) pointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
endinterface

interface Rtest;
   interface RtestRequest request;
   interface MemReadClient#(64) dmaClient;
endinterface

interface RtestIndication;
   method Action readDone(Bit#(32) mismatchCount);
endinterface

module mkRtest#(RtestIndication indication) (Rtest);

   Reg#(SGLId)   pointer <- mkReg(0);
   Reg#(Bit#(32))       numWords <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstLenBytes <- mkReg(0);
   FIFO#(void)                cf <- mkSizedFIFO(1);
   Reg#(Bit#(32))  itersToFinish <- mkReg(0);
   Reg#(Bit#(32))   itersToStart <- mkReg(0);
   Reg#(Bit#(32))        srcGens <- mkReg(0);
   Reg#(Bit#(32)) mismatchCounts <- mkReg(0);
   MemreadEngine#(64,8,1)        re <- mkMemreadEngine;
   Bit#(32)             numBytes = extend(numWords)*4;

   rule start (itersToStart > 0);
      re.readServers[0].request.put(MemengineCmd{sglId:pointer, base:0, len:numBytes, burstLen:burstLenBytes});
      itersToStart <= itersToStart-1;
   endrule

   rule check;
      let v <- toGet(re.dataPipes[0]).get;
      let expectedV = {srcGens+1,srcGens};
      let misMatch = v != expectedV;
      mismatchCounts <= mismatchCounts + (misMatch ? 1 : 0);
      let new_srcGens = srcGens+2;
      if (new_srcGens >= truncate(numBytes/4))
	 new_srcGens = 0;
      srcGens <= new_srcGens;
   endrule

   rule finish if (itersToFinish > 0);
      let rv <- re.readServers[0].response.get;
      if (itersToFinish == 1) begin
	 cf.deq;
	 indication.readDone(mismatchCounts);
      end
      itersToFinish <= itersToFinish - 1;
   endrule

   interface dmaClient = re.dmaClient;
   interface RtestRequest request;
      method Action startRead(Bit#(32) rp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic) if (itersToStart == 0 && itersToFinish == 0);
	 pointer <= rp;
	 cf.enq(?);
	 numWords  <= nw;
	 burstLenBytes  <= truncate(bl*4);
	 itersToFinish <= ic;
	 itersToStart <= ic;
	 mismatchCounts <= 0;
	 srcGens <= 0;
      endmethod
   endinterface
endmodule


pipeline mkMemReaderBuff and mkMemWriterBuff

Change-Id: I399b60a9e85ec27e7266a6c2f8b3623b4007ff65

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import BRAM::*;
import FIFO::*;
import Vector::*;
import Gearbox::*;
import FIFOF::*;
import SpecialFIFOs::*;
import GetPut::*;

import MemTypes::*;
import ConfigCounter::*;
import BRAMFIFOFLevel::*;

interface MemReader#(numeric type dataWidth);
   interface ObjectReadServer #(dataWidth) readServer;
   interface ObjectReadClient#(dataWidth) readClient;
endinterface

module mkMemReader(MemReader#(dataWidth))
   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFOF#(ObjectData#(dataWidth)) readBuffer <- mkFIFOF;
   FIFOF#(ObjectRequest)           reqBuffer <- mkFIFOF;

   interface ObjectReadServer readServer;
      interface Put readReq = toPut(reqBuffer);
      interface Get readData = toGet(readBuffer);
   endinterface
   interface ObjectReadClient readClient;
      interface Get readReq = toGet(reqBuffer);
      interface Put readData = toPut(readBuffer);
   endinterface
endmodule

interface MemReaderBuff#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectReadServer #(dataWidth) readServer;
   interface ObjectReadClient#(dataWidth) readClient;
endinterface

module mkMemReaderBuff(MemReaderBuff#(dataWidth, bufferDepth))
   provisos(Div#(dataWidth,8,dataWidthBytes)
	    ,Mul#(dataWidthBytes,8,dataWidth)
	    ,Log#(dataWidthBytes,beatShift)
	    ,Log#(bufferDepth, a__)
	    ,Add#(a__, 1, b__)
	    ,Add#(TLog#(bufferDepth), c__, 15)
	    );

   FIFOFLevel#(ObjectData#(dataWidth),bufferDepth)  readBuffer <- mkBRAMFIFOFLevel;
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(ObjectRequest)          reqCommitted <- mkFIFOF();
   ConfigCounter#(16) unfulfilled <- mkConfigCounter(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   // only issue the readRequest when sufficient buffering is available.  This includes the bufering we have already comitted.
   Bit#(16) sreq = pack(satPlus(Sat_Bound, unpack(extend(reqOutstanding.first.burstLen>>beat_shift)), unfulfilled.read()));

   rule commitReq if (readBuffer.lowWater(truncate(sreq)));
      let req <- toGet(reqOutstanding).get();
      unfulfilled.increment(unpack(extend(req.burstLen>>beat_shift)));
      reqCommitted.enq(req);
   endrule

   interface ObjectReadServer readServer;
      interface Put readReq = toPut(reqOutstanding);
      interface Get readData = toGet(readBuffer);
   endinterface
   interface ObjectReadClient readClient;
      interface Get readReq = toGet(reqCommitted);
      interface Put readData;
   	 method Action put(ObjectData#(dataWidth) x);
   	    readBuffer.fifo.enq(x);
   	    unfulfilled.decrement(1);
   	 endmethod
      endinterface
   endinterface
endmodule

interface MemWriter#(numeric type dataWidth);
   interface ObjectWriteServer#(dataWidth) writeServer;
   interface ObjectWriteClient#(dataWidth) writeClient;
endinterface

module mkMemWriter(MemWriter#(dataWidth))
   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFOF#(ObjectData#(dataWidth)) writeBuffer <- mkFIFOF;
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF;
   FIFOF#(Bit#(6))                        doneTags <- mkFIFOF();

   interface ObjectWriteServer writeServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData = toPut(writeBuffer);
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient writeClient;
      interface Get writeReq = toGet(reqOutstanding);
      interface Get writeData = toGet(writeBuffer);
      interface Put writeDone = toPut(doneTags);
   endinterface

endmodule

interface MemWriterBuff#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectWriteServer#(dataWidth) writeServer;
   interface ObjectWriteClient#(dataWidth) writeClient;
endinterface

module mkMemWriterBuff(MemWriterBuff#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1, TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFOFLevel#(ObjectData#(dataWidth),bufferDepth) writeBuffer <- mkBRAMFIFOFLevel;
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(ObjectRequest)        reqCommitted <- mkFIFOF();
   FIFOF#(Bit#(6))                        doneTags <- mkFIFOF();
   ConfigCounter#(TAdd#(1,TLog#(bufferDepth)))  unfulfilled <- mkConfigCounter(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   // only issue the writeRequest when sufficient data is available.  This includes the data we have already comitted.
   Bit#(TAdd#(1,TLog#(bufferDepth))) sreq = pack(satPlus(Sat_Bound, unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)), unfulfilled.read()));

   rule commitReq if (writeBuffer.highWater(sreq));
      let req <- toGet(reqOutstanding).get();
      unfulfilled.increment(unpack(truncate(req.burstLen>>beat_shift)));
      reqCommitted.enq(req);
   endrule

   interface ObjectWriteServer writeServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData = toPut(writeBuffer);
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient writeClient;
      interface Get writeReq = toGet(reqCommitted);
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    unfulfilled.decrement(1);
	    writeBuffer.fifo.deq;
	    return writeBuffer.fifo.first;
	 endmethod
      endinterface
      interface Put writeDone = toPut(doneTags);
   endinterface
endmodule

interface UGBramFifos#(numeric type numFifos, numeric type fifoDepth, type a);
   method Action enq(Bit#(TLog#(numFifos)) idx, a v);
   method Action first_req(Bit#(TLog#(numFifos)) idx);
   method ActionValue#(a) first_resp();
   method Action deq(Bit#(TLog#(numFifos)) idx);
   method Action upd_head(Bit#(TLog#(numFifos)) idx, a v);
endinterface

module mkUGBramFifos(UGBramFifos#(numFifos,fifoDepth,a))
   provisos(Mul#(fifoDepth,numFifos,buffSz),
	    Log#(buffSz, buffAddrSz),
	    Add#(a__, TLog#(numFifos), TAdd#(1, buffAddrSz)),
	    Bits#(a,b__));

   function Bit#(buffAddrSz) hf(Integer i) = fromInteger(i*valueOf(fifoDepth));
   Vector#(numFifos, Reg#(Bit#(buffAddrSz))) head <- mapM(mkReg, genWith(hf));
   Vector#(numFifos, Reg#(Bit#(buffAddrSz))) tail <- mapM(mkReg, genWith(hf));
   BRAM2Port#(Bit#(buffAddrSz),a)    buff <- mkBRAM2Server(defaultValue);
   let fifo_depth = fromInteger(valueOf(fifoDepth));

   method Action enq(Bit#(TLog#(numFifos)) idx, a v);
      buff.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tail[idx], datain:v});
      Bit#(TAdd#(1,buffAddrSz)) nt = extend(tail[idx])+1;
      Bit#(TAdd#(1,buffAddrSz)) li = (extend(idx)+1)*fifo_depth;
      Bit#(TAdd#(1,buffAddrSz)) rs = (extend(idx)+0)*fifo_depth;
      if (nt >= li)
	 nt = rs;
      tail[idx] <= truncate(nt);
   endmethod

   method Action first_req(Bit#(TLog#(numFifos)) idx);
      buff.portA.request.put(BRAMRequest{write:False, responseOnWrite:False, address:head[idx], datain:?});
   endmethod

   method ActionValue#(a) first_resp();
      let v <- buff.portA.response.get;
      return v;
   endmethod

   method Action deq(Bit#(TLog#(numFifos)) idx);
      Bit#(TAdd#(1,buffAddrSz)) nt = extend(head[idx])+1;
      Bit#(TAdd#(1,buffAddrSz)) li = (extend(idx)+1)*fifo_depth;
      Bit#(TAdd#(1,buffAddrSz)) rs = (extend(idx)+0)*fifo_depth;
      if (nt >= li)
	 nt = rs;
      head[idx] <= truncate(nt);
   endmethod

   method Action upd_head(Bit#(TLog#(numFifos)) idx, a v);
      buff.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head[idx], datain:v});
   endmethod

endmodule

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import BRAM::*;
import FIFO::*;
import Vector::*;
import Gearbox::*;
import FIFOF::*;
import SpecialFIFOs::*;
import GetPut::*;

import MemTypes::*;
import ConfigCounter::*;
import BRAMFIFOFLevel::*;

interface MemReader#(numeric type dataWidth);
   interface ObjectReadServer #(dataWidth) readServer;
   interface ObjectReadClient#(dataWidth) readClient;
endinterface

module mkMemReader(MemReader#(dataWidth))
   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFOF#(ObjectData#(dataWidth)) readBuffer <- mkFIFOF;
   FIFOF#(ObjectRequest)           reqBuffer <- mkFIFOF;

   interface ObjectReadServer readServer;
      interface Put readReq = toPut(reqBuffer);
      interface Get readData = toGet(readBuffer);
   endinterface
   interface ObjectReadClient readClient;
      interface Get readReq = toGet(reqBuffer);
      interface Put readData = toPut(readBuffer);
   endinterface
endmodule

interface MemReaderBuff#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectReadServer #(dataWidth) readServer;
   interface ObjectReadClient#(dataWidth) readClient;
endinterface

module mkMemReaderBuff(MemReaderBuff#(dataWidth, bufferDepth))
   provisos(Div#(dataWidth,8,dataWidthBytes)
	    ,Mul#(dataWidthBytes,8,dataWidth)
	    ,Log#(dataWidthBytes,beatShift)
	    ,Log#(bufferDepth, a__)
	    ,Add#(a__, 1, b__)
	    ,Add#(TLog#(bufferDepth), c__, 15)
	    );

   FIFOFLevel#(ObjectData#(dataWidth),bufferDepth)  readBuffer <- mkBRAMFIFOFLevel;
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   ConfigCounter#(16) unfulfilled <- mkConfigCounter(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   // only issue the readRequest when sufficient buffering is available.  This includes the bufering we have already comitted.
   Bit#(16) sreq = pack(satPlus(Sat_Bound, unpack(extend(reqOutstanding.first.burstLen>>beat_shift)), unfulfilled.read()));

   interface ObjectReadServer readServer;
      interface Put readReq = toPut(reqOutstanding);
      interface Get readData = toGet(readBuffer);
   endinterface
   interface ObjectReadClient readClient;
      interface Get readReq;
   	 method ActionValue#(ObjectRequest) get if (readBuffer.lowWater(truncate(sreq)));
   	    reqOutstanding.deq;
   	    unfulfilled.increment(unpack(extend(reqOutstanding.first.burstLen>>beat_shift)));
   	    return reqOutstanding.first;
   	 endmethod
      endinterface
      interface Put readData;
   	 method Action put(ObjectData#(dataWidth) x);
   	    readBuffer.fifo.enq(x);
   	    unfulfilled.decrement(1);
   	 endmethod
      endinterface
   endinterface
endmodule

interface MemWriter#(numeric type dataWidth);
   interface ObjectWriteServer#(dataWidth) writeServer;
   interface ObjectWriteClient#(dataWidth) writeClient;
endinterface

module mkMemWriter(MemWriter#(dataWidth))
   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFOF#(ObjectData#(dataWidth)) writeBuffer <- mkFIFOF;
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF;
   FIFOF#(Bit#(6))                        doneTags <- mkFIFOF();

   interface ObjectWriteServer writeServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData = toPut(writeBuffer);
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient writeClient;
      interface Get writeReq = toGet(reqOutstanding);
      interface Get writeData = toGet(writeBuffer);
      interface Put writeDone = toPut(doneTags);
   endinterface

endmodule

interface MemWriterBuff#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectWriteServer#(dataWidth) writeServer;
   interface ObjectWriteClient#(dataWidth) writeClient;
endinterface

module mkMemWriterBuff(MemWriterBuff#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1, TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFOFLevel#(ObjectData#(dataWidth),bufferDepth) writeBuffer <- mkBRAMFIFOFLevel;
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(Bit#(6))                        doneTags <- mkFIFOF();
   ConfigCounter#(TAdd#(1,TLog#(bufferDepth)))  unfulfilled <- mkConfigCounter(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   // only issue the writeRequest when sufficient data is available.  This includes the data we have already comitted.
   Bit#(TAdd#(1,TLog#(bufferDepth))) sreq = pack(satPlus(Sat_Bound, unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)), unfulfilled.read()));

   interface ObjectWriteServer writeServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData = toPut(writeBuffer);
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient writeClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get if (writeBuffer.highWater(sreq));
	    reqOutstanding.deq;
	    unfulfilled.increment(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    unfulfilled.decrement(1);
	    writeBuffer.fifo.deq;
	    return writeBuffer.fifo.first;
	 endmethod
      endinterface
      interface Put writeDone = toPut(doneTags);
   endinterface
endmodule

interface UGBramFifos#(numeric type numFifos, numeric type fifoDepth, type a);
   method Action enq(Bit#(TLog#(numFifos)) idx, a v);
   method Action first_req(Bit#(TLog#(numFifos)) idx);
   method ActionValue#(a) first_resp();
   method Action deq(Bit#(TLog#(numFifos)) idx);
   method Action upd_head(Bit#(TLog#(numFifos)) idx, a v);
endinterface

module mkUGBramFifos(UGBramFifos#(numFifos,fifoDepth,a))
   provisos(Mul#(fifoDepth,numFifos,buffSz),
	    Log#(buffSz, buffAddrSz),
	    Add#(a__, TLog#(numFifos), TAdd#(1, buffAddrSz)),
	    Bits#(a,b__));

   function Bit#(buffAddrSz) hf(Integer i) = fromInteger(i*valueOf(fifoDepth));
   Vector#(numFifos, Reg#(Bit#(buffAddrSz))) head <- mapM(mkReg, genWith(hf));
   Vector#(numFifos, Reg#(Bit#(buffAddrSz))) tail <- mapM(mkReg, genWith(hf));
   BRAM2Port#(Bit#(buffAddrSz),a)    buff <- mkBRAM2Server(defaultValue);
   let fifo_depth = fromInteger(valueOf(fifoDepth));

   method Action enq(Bit#(TLog#(numFifos)) idx, a v);
      buff.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tail[idx], datain:v});
      Bit#(TAdd#(1,buffAddrSz)) nt = extend(tail[idx])+1;
      Bit#(TAdd#(1,buffAddrSz)) li = (extend(idx)+1)*fifo_depth;
      Bit#(TAdd#(1,buffAddrSz)) rs = (extend(idx)+0)*fifo_depth;
      if (nt >= li)
	 nt = rs;
      tail[idx] <= truncate(nt);
   endmethod

   method Action first_req(Bit#(TLog#(numFifos)) idx);
      buff.portA.request.put(BRAMRequest{write:False, responseOnWrite:False, address:head[idx], datain:?});
   endmethod

   method ActionValue#(a) first_resp();
      let v <- buff.portA.response.get;
      return v;
   endmethod

   method Action deq(Bit#(TLog#(numFifos)) idx);
      Bit#(TAdd#(1,buffAddrSz)) nt = extend(head[idx])+1;
      Bit#(TAdd#(1,buffAddrSz)) li = (extend(idx)+1)*fifo_depth;
      Bit#(TAdd#(1,buffAddrSz)) rs = (extend(idx)+0)*fifo_depth;
      if (nt >= li)
	 nt = rs;
      head[idx] <= truncate(nt);
   endmethod

   method Action upd_head(Bit#(TLog#(numFifos)) idx, a v);
      buff.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head[idx], datain:v});
   endmethod

endmodule