simplfied MIFO

simplfied MIFO

// 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(mkFIFOF());

   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(mkFIFOF());

   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
      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));
		    weFifo.enq(pack(rotateBy(we, inPos)));
		    posFifo.enq(inPos);
		    inPos <= truncate((extend(inPos) + extend(i_n_in)) % i_max_out);

		    if (verbose) $display("enq: inPos=%d we=%h", inPos, we);
		 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


simplified pcie3 connections in mkPcieHost

// Copyright (c) 2014-2015 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 BuildVector       :: *;
import Clocks            :: *;
import GetPut            :: *;
import FIFO              :: *;
import Connectable       :: *;
import ClientServer      :: *;
import BRAM              :: *;
import DefaultValue      :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import Xilinx            :: *;
import Bscan             :: *;
import Portal            :: *;
import MemToPcie    :: *;
import PcieToMem   :: *;
import PcieCsr           :: *;
import MemTypes          :: *;
`ifndef BSIM
`ifdef XILINX
`ifdef PCIE1
import PCIEWRAPPER       :: *;
import PcieEndpointX7    :: *;
`endif // pcie1
`ifdef PCIE2
import PCIEWRAPPER2       :: *;
import PcieEndpointX7Gen2 :: *;
`endif // pcie2
`ifdef PCIE3
import PCIEWRAPPER3      :: *;
import Pcie3EndpointX7   :: *;
`endif // pcie3
`elsif ALTERA
import PcieEndpointS5    :: *;
`elsif VSIM
import PcieEndpointS5    :: *;
`endif
`endif
import HostInterface     :: *;

// implemented in TlpReplay.cpp
import "BDPI" function Action put_tlp(TLPData#(16) d);
import "BDPI" function ActionValue#(TLPData#(16)) get_tlp();
import "BDPI" function Bool can_put_tlp();
import "BDPI" function Bool can_get_tlp();

(* synthesize *)
module mkMemToPcieSynth#(PciId my_id)(MemToPcie#(DataBusWidth));
   let memSlaveEngine <- mkMemToPcie(my_id);
   return memSlaveEngine;
endmodule

// ==================================================
// PCIE Gen3  PcieHost
//
`ifdef PCIE3
Integer tlpCompleterRequest = 0;
Integer tlpRequesterRequest = 1;

(* synthesize *)
module mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   TLPDispatcher dispatcher <- mkTLPDispatcher;
   TLPArbiter arbiter <- mkTLPArbiter;
   MemToPcie#(DataBusWidth) sEngine <- mkMemToPcieSynth(my_pciId);
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
   Vector#(PortMax, PcieToMem) mvec;
   for (Integer i=0; i < valueOf(PortMax) - 1; i=i+1) begin
      let tlp;
      if (i == portInterrupt)
         tlp = intr.tlp;
      else begin
         mvec[i] <- mkPcieToMem(my_pciId);
         tlp = mvec[i].tlp;
      end
      mkConnection((interface Server;
                       interface response = dispatcher.out[i];
                       interface request = arbiter.in[i];
                    endinterface), tlp);
   end

   PcieTracer traceif <- mkPcieTracer();
   let splitter = (interface Client;
                      interface request = arbiter.outToBus;
                      interface response = dispatcher.inFromBus;
                  endinterface);
`ifdef TRACE_PORTAL
   mkConnection(traceif[tlpCompleterRequest].bus, splitter);
`else
   mkConnection(traceif.bus, sEngine.tlp);
`endif

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs();
   mkConnection(mvec[portConfig].master, csr.memSlave);

   mkConnection(csr.traceClient, traceif.traceServer);
   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = vec(sEngine.slave);
   interface interruptRequest = intr.interruptRequest;
`ifdef TRACE_PORTAL
   interface pcic = traceif.pci;
   interface pcir = sEngine.tlp;
`else
   interface pcic = splitter;
   interface pcir = traceif.pci;
`endif
endmodule: mkPcieHost
`else //NOT PCIE3
// ======================================================
// PCIE GEN1 and GEN2 PcieHost
//(* synthesize *) commented out so that the guards in MemServer aren't destroyed (mdk)
module  mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   let dispatcher <- mkTLPDispatcher;
   let arbiter    <- mkTLPArbiter;
   Vector#(NumberOfMasters,MemToPcie#(DataBusWidth)) sEngine <- replicateM(mkMemToPcieSynth(my_pciId));
   Vector#(NumberOfMasters,PhysMemSlave#(PciePhysAddrWidth,DataBusWidth)) slavearr;
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
`ifdef PCIE_BSCAN
   BscanTop bscan <- mkBscanTop(3); // Use USER3  (JTAG IDCODE address 0x22)
   BscanLocal lbscan <- mkBscanLocal(bscan, clocked_by bscan.tck, reset_by bscan.rst);
`endif

   Vector#(PortMax, PcieToMem) mvec;
   for (Integer i = 0; i < valueOf(PortMax) - 1 + valueOf(NumberOfMasters); i=i+1) begin
       let tlp;
       if (i == portInterrupt)
           tlp = intr.tlp;
       else if (i >= portAxi) begin
           tlp = sEngine[i - portAxi].tlp;
           slavearr[i - portAxi] = sEngine[i - portAxi].slave;
       end
       else begin
           mvec[i] <- mkPcieToMem(my_pciId);
           tlp = mvec[i].tlp;
       end
       mkConnection((interface Server;
                        interface response = dispatcher.out[i];
                        interface request = arbiter.in[i];
                     endinterface), tlp);
   end

   PcieTracer  traceif <- mkPcieTracer();
   mkConnection(traceif.bus, (interface Client;
                                 interface request = arbiter.outToBus;
                                 interface response = dispatcher.inFromBus;
                              endinterface));

`ifndef BSIM
`ifdef PCIE_BSCAN
   Reg#(Bit#(TAdd#(TlpTraceAddrSize,1))) bscanPcieTraceBramWrAddrReg <- mkReg(0);
   BscanBram#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) pcieBscanBram <- mkBscanBram(127, bscanPcieTraceBramWrAddrReg, lbscan.loc[1]);
   mkConnection(pcieBscanBram.bramClient, traceif.tlpdata.bscanBramServer);
   rule tdorule;
      lbscan.loc[1].tdo(pcieBscanBram.data_out());
   endrule
`endif
`endif

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs;
   mkConnection(mvec[portConfig].master, csr.memSlave);
   mkConnection(csr.traceClient, traceif.traceServer);

   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = slavearr;
   interface interruptRequest = intr.interruptRequest;
   interface pci = traceif.pci;
`ifdef PCIE_BSCAN
   interface BscanTop bscanif = lbscan.loc[0];
`else
`ifdef PCIE_TRACE_PORT
   interface BRAMServer traceBramServer = traceif.tlpdata.bscanBramServer;
`endif
`endif
endmodule: mkPcieHost
`endif //PCIE3

interface PcieTop#(type ipins);
`ifndef BSIM
   (* prefix="PCIE" *)
   interface PciewrapPci_exp#(PcieLanes) pcie;
   (* always_ready *)
   (* prefix="" *)
   interface ipins       pins;
`endif
endinterface

`ifdef BSIM
module mkBsimPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   let dc <- exposeCurrentClock;
   let dr <- exposeCurrentReset;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(PciId{ bus:0, dev:0, func:0});
   // connect pciehost.pci to bdip functions here
   rule from_bdpi if (can_get_tlp);
      TLPData#(16) foo <- get_tlp;
      pciehost.pci.response.put(foo);
      //$display("from_bdpi: %h %d", foo, valueOf(SizeOf#(TLPData#(16))));
   endrule
   rule to_bdpi if (can_put_tlp);
      TLPData#(16) foo <- pciehost.pci.request.get;
      put_tlp(foo);
      //$display("to_bdpi");
   endrule
   interface Clock pcieClock = dc;
   interface Reset pcieReset = dr;
   interface PcieHost tpciehost = pciehost;
endmodule
`endif

`ifdef XILINX
(* no_default_clock, no_default_reset *)
module mkXilinxPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);

// Clock and PcieEndpoint for Xilinx
   Clock sys_clk_200mhz <- mkClockIBUFDS(
`ifdef ClockDefaultParam
       defaultValue,
`endif
       sys_clk_p, sys_clk_n);
   Clock sys_clk_200mhz_buf <- mkClockBUFG(clocked_by sys_clk_200mhz);
   Clock pci_clk_100mhz_buf <- mkClockIBUFDS_GTE2(
`ifdef ClockDefaultParam
       defaultValue,
`endif
       True, pci_sys_clk_p, pci_sys_clk_n);
   // Instantiate the PCIE endpoint
   PcieEndpointX7#(PcieLanes) ep7 <- mkPcieEndpointX7( clocked_by pci_clk_100mhz_buf, reset_by pci_sys_reset_n);

   Clock pcieClock_ = ep7.epPcieClock;
   Reset pcieReset_ = ep7.epPcieReset;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(
`ifdef PCIE3
         PciId{bus: 0, dev: 0, func:0},
`else
         PciId{ bus:  ep7.cfg.bus_number(), dev: ep7.cfg.device_number(), func: ep7.cfg.function_number()},
`endif
         clocked_by pcieClock_, reset_by pcieReset_);
`ifdef PCIE3
   mkConnection(ep7.tlpr, pciehost.pcir, clocked_by pcieClock_, reset_by pcieReset_);
   mkConnection(ep7.tlpc, pciehost.pcic, clocked_by pcieClock_, reset_by pcieReset_);
`else
   mkConnection(ep7.tlp, pciehost.pci, clocked_by pcieClock_, reset_by pcieReset_);
`endif

   interface Clock tsys_clk_200mhz = sys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf = sys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf = pci_clk_100mhz_buf;

   interface PcieEndpointX7 tep7 = ep7;
   interface PcieHost tpciehost = pciehost;

   interface pcieClock = ep7.epPcieClock;
   interface pcieReset = ep7.epPcieReset;
   interface portalClock = ep7.epPortalClock;
   interface portalReset = ep7.epPortalReset;
   interface derivedClock = ep7.epDerivedClock;
   interface derivedReset = ep7.epDerivedReset;
endmodule
`endif

`ifdef ALTERA
`define ALTERA_TOP
`elsif VSIM
`define ALTERA_TOP
`endif

`ifdef ALTERA_TOP
(* no_default_clock, no_default_reset *)
module mkAlteraPcieHostTop #(Clock clk_100MHz, Clock clk_50MHz, Reset perst_n)(PcieHostTop);

   PcieEndpointS5#(PcieLanes) ep7 <- mkPcieEndpointS5(clk_100MHz, clk_50MHz, perst_n, clocked_by clk_100MHz, reset_by perst_n);

   Clock epPcieClock = ep7.epPcieClock;
   Reset epPcieReset = ep7.epPcieReset;

   Clock portalClock_ = epPcieClock;
   Reset portalReset_ = epPcieReset;

   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(ep7.device, clocked_by portalClock_, reset_by portalReset_);
   mkConnection(ep7.tlp, pciehost.pci, clocked_by portalClock_, reset_by portalReset_);

   interface PcieEndpointS5 tep7 = ep7;
   interface PcieHost tpciehost = pciehost;

   interface Clock pcieClock = epPcieClock;
   interface Reset pcieReset = epPcieReset;
   interface portalClock = portalClock_;
   interface portalReset = portalReset_;
   interface derivedClock = ep7.epDerivedClock;
   interface derivedReset = ep7.epDerivedReset;

endmodule
`endif

`ifdef BSIM
   module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   PcieHostTop _a <- mkBsimPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n); return _a;
   endmodule
`elsif XILINX // XILINX
   //(* synthesize, no_default_clock, no_default_reset *)
   (* no_default_clock, no_default_reset *)
   module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
      PcieHostTop _a <- mkXilinxPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n); return _a;
   endmodule
`elsif ALTERA_TOP
   //(* synthesize, no_default_clock, no_default_reset *)
   (* no_default_clock, no_default_reset *)
   module mkPcieHostTop #(Clock clk_100MHz, Clock clk_50MHz, Reset perst_n)(PcieHostTop);
      PcieHostTop _a <- mkAlteraPcieHostTop(clk_100MHz, clk_50MHz, perst_n); return _a;
   endmodule
`endif // NOT ALTERA

// Copyright (c) 2014-2015 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 Clocks            :: *;
import GetPut            :: *;
import FIFO              :: *;
import Connectable       :: *;
import ClientServer      :: *;
import BRAM              :: *;
import DefaultValue      :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import Xilinx            :: *;
import Bscan             :: *;
import Portal            :: *;
import MemToPcie    :: *;
import PcieToMem   :: *;
import PcieCsr           :: *;
import MemTypes          :: *;
`ifndef BSIM
`ifdef XILINX
`ifdef PCIE1
import PCIEWRAPPER       :: *;
import PcieEndpointX7    :: *;
`endif // pcie1
`ifdef PCIE2
import PCIEWRAPPER2       :: *;
import PcieEndpointX7Gen2 :: *;
`endif // pcie2
`ifdef PCIE3
import PCIEWRAPPER3      :: *;
import Pcie3EndpointX7   :: *;
`endif // pcie3
`elsif ALTERA
import PcieEndpointS5    :: *;
`elsif VSIM
import PcieEndpointS5    :: *;
`endif
`endif
import HostInterface     :: *;

// implemented in TlpReplay.cpp
import "BDPI" function Action put_tlp(TLPData#(16) d);
import "BDPI" function ActionValue#(TLPData#(16)) get_tlp();
import "BDPI" function Bool can_put_tlp();
import "BDPI" function Bool can_get_tlp();

(* synthesize *)
module mkMemToPcieSynth#(PciId my_id)(MemToPcie#(DataBusWidth));
   let memSlaveEngine <- mkMemToPcie(my_id);
   return memSlaveEngine;
endmodule

// ==================================================
// PCIE Gen3  PcieHost
//
`ifdef PCIE3
Integer tlpCompleterRequest = 0;
Integer tlpRequesterRequest = 1;
typedef 2   NumberOfTlpIntfs;

(* synthesize *)
module mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   Vector#(NumberOfTlpIntfs, TLPDispatcher) dispatcher <- replicateM(mkTLPDispatcher);
   Vector#(NumberOfTlpIntfs, TLPArbiter) arbiter <- replicateM(mkTLPArbiter);
   Vector#(NumberOfMasters, MemToPcie#(DataBusWidth)) sEngine <- replicateM(mkMemToPcieSynth(my_pciId));
   Vector#(NumberOfMasters,PhysMemSlave#(PciePhysAddrWidth,DataBusWidth)) slavearr;
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
   Vector#(PortMax, PcieToMem) mvec;
   for (Integer i=0; i < valueOf(NumberOfMasters); i=i+1) begin
      let tlp;
      tlp = sEngine[i].tlp;
      slavearr[i]  = sEngine[i].slave;
      mkConnection((interface Server;
                       interface response = dispatcher[tlpRequesterRequest].out[i];
                       interface request = arbiter[tlpRequesterRequest].in[i];
                    endinterface), tlp);
   end
   for (Integer i=0; i < valueOf(PortMax) - 1; i=i+1) begin
      let tlp;
      if (i == portInterrupt)
         tlp = intr.tlp;
      else begin
         mvec[i] <- mkPcieToMem(my_pciId);
         tlp = mvec[i].tlp;
      end
      mkConnection((interface Server;
                       interface response = dispatcher[tlpCompleterRequest].out[i];
                       interface request = arbiter[tlpCompleterRequest].in[i];
                    endinterface), tlp);
   end

   Vector#(NumberOfTlpIntfs, PcieTracer) traceif <- replicateM(mkPcieTracer());
   mkConnection(traceif[tlpCompleterRequest].bus, (interface Client;
                                    interface request = arbiter[tlpCompleterRequest].outToBus;
                                    interface response = dispatcher[tlpCompleterRequest].inFromBus;
                                 endinterface));
   mkConnection(traceif[tlpRequesterRequest].bus, (interface Client;
                                    interface request = arbiter[tlpRequesterRequest].outToBus;
                                    interface response = dispatcher[tlpRequesterRequest].inFromBus;
                                 endinterface));

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs();
   mkConnection(mvec[portConfig].master, csr.memSlave);

   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = slavearr;
   interface interruptRequest = intr.interruptRequest;
   interface pcic = traceif[tlpCompleterRequest].pci;
   interface pcir = traceif[tlpRequesterRequest].pci;
endmodule: mkPcieHost
`else //NOT PCIE3
// ======================================================
// PCIE GEN1 and GEN2 PcieHost
//(* synthesize *) commented out so that the guards in MemServer aren't destroyed (mdk)
module  mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   let dispatcher <- mkTLPDispatcher;
   let arbiter    <- mkTLPArbiter;
   Vector#(NumberOfMasters,MemToPcie#(DataBusWidth)) sEngine <- replicateM(mkMemToPcieSynth(my_pciId));
   Vector#(NumberOfMasters,PhysMemSlave#(PciePhysAddrWidth,DataBusWidth)) slavearr;
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
`ifdef PCIE_BSCAN
   BscanTop bscan <- mkBscanTop(3); // Use USER3  (JTAG IDCODE address 0x22)
   BscanLocal lbscan <- mkBscanLocal(bscan, clocked_by bscan.tck, reset_by bscan.rst);
`endif

   Vector#(PortMax, PcieToMem) mvec;
   for (Integer i = 0; i < valueOf(PortMax) - 1 + valueOf(NumberOfMasters); i=i+1) begin
       let tlp;
       if (i == portInterrupt)
           tlp = intr.tlp;
       else if (i >= portAxi) begin
           tlp = sEngine[i - portAxi].tlp;
           slavearr[i - portAxi] = sEngine[i - portAxi].slave;
       end
       else begin
           mvec[i] <- mkPcieToMem(my_pciId);
           tlp = mvec[i].tlp;
       end
       mkConnection((interface Server;
                        interface response = dispatcher.out[i];
                        interface request = arbiter.in[i];
                     endinterface), tlp);
   end

   PcieTracer  traceif <- mkPcieTracer();
   mkConnection(traceif.bus, (interface Client;
                                 interface request = arbiter.outToBus;
                                 interface response = dispatcher.inFromBus;
                              endinterface));

`ifndef BSIM
`ifdef PCIE_BSCAN
   Reg#(Bit#(TAdd#(TlpTraceAddrSize,1))) bscanPcieTraceBramWrAddrReg <- mkReg(0);
   BscanBram#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) pcieBscanBram <- mkBscanBram(127, bscanPcieTraceBramWrAddrReg, lbscan.loc[1]);
   mkConnection(pcieBscanBram.bramClient, traceif.tlpdata.bscanBramServer);
   rule tdorule;
      lbscan.loc[1].tdo(pcieBscanBram.data_out());
   endrule
`endif
`endif

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs;
   mkConnection(mvec[portConfig].master, csr.memSlave);
   mkConnection(csr.traceClient, traceif.traceServer);

   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = slavearr;
   interface interruptRequest = intr.interruptRequest;
   interface pci = traceif.pci;
`ifdef PCIE_BSCAN
   interface BscanTop bscanif = lbscan.loc[0];
`else
`ifdef PCIE_TRACE_PORT
   interface BRAMServer traceBramServer = traceif.tlpdata.bscanBramServer;
`endif
`endif
endmodule: mkPcieHost
`endif //PCIE3

interface PcieTop#(type ipins);
`ifndef BSIM
   (* prefix="PCIE" *)
   interface PciewrapPci_exp#(PcieLanes) pcie;
   (* always_ready *)
   (* prefix="" *)
   interface ipins       pins;
`endif
endinterface

`ifdef BSIM
module mkBsimPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   let dc <- exposeCurrentClock;
   let dr <- exposeCurrentReset;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(PciId{ bus:0, dev:0, func:0});
   // connect pciehost.pci to bdip functions here
   rule from_bdpi if (can_get_tlp);
      TLPData#(16) foo <- get_tlp;
      pciehost.pci.response.put(foo);
      //$display("from_bdpi: %h %d", foo, valueOf(SizeOf#(TLPData#(16))));
   endrule
   rule to_bdpi if (can_put_tlp);
      TLPData#(16) foo <- pciehost.pci.request.get;
      put_tlp(foo);
      //$display("to_bdpi");
   endrule
   interface Clock pcieClock = dc;
   interface Reset pcieReset = dr;
   interface PcieHost tpciehost = pciehost;
endmodule
`endif

`ifdef XILINX
(* no_default_clock, no_default_reset *)
module mkXilinxPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);

// Clock and PcieEndpoint for Xilinx
   Clock sys_clk_200mhz <- mkClockIBUFDS(
`ifdef ClockDefaultParam
       defaultValue,
`endif
       sys_clk_p, sys_clk_n);
   Clock sys_clk_200mhz_buf <- mkClockBUFG(clocked_by sys_clk_200mhz);
   Clock pci_clk_100mhz_buf <- mkClockIBUFDS_GTE2(
`ifdef ClockDefaultParam
       defaultValue,
`endif
       True, pci_sys_clk_p, pci_sys_clk_n);
   // Instantiate the PCIE endpoint
   PcieEndpointX7#(PcieLanes) ep7 <- mkPcieEndpointX7( clocked_by pci_clk_100mhz_buf, reset_by pci_sys_reset_n);

   Clock pcieClock_ = ep7.epPcieClock;
   Reset pcieReset_ = ep7.epPcieReset;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(
`ifdef PCIE3
         PciId{bus: 0, dev: 0, func:0},
`else
         PciId{ bus:  ep7.cfg.bus_number(), dev: ep7.cfg.device_number(), func: ep7.cfg.function_number()},
`endif
         clocked_by pcieClock_, reset_by pcieReset_);
`ifdef PCIE3
   mkConnection(ep7.tlpr, pciehost.pcir, clocked_by pcieClock_, reset_by pcieReset_);
   mkConnection(ep7.tlpc, pciehost.pcic, clocked_by pcieClock_, reset_by pcieReset_);
`else
   mkConnection(ep7.tlp, pciehost.pci, clocked_by pcieClock_, reset_by pcieReset_);
`endif

   interface Clock tsys_clk_200mhz = sys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf = sys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf = pci_clk_100mhz_buf;

   interface PcieEndpointX7 tep7 = ep7;
   interface PcieHost tpciehost = pciehost;

   interface pcieClock = ep7.epPcieClock;
   interface pcieReset = ep7.epPcieReset;
   interface portalClock = ep7.epPortalClock;
   interface portalReset = ep7.epPortalReset;
   interface derivedClock = ep7.epDerivedClock;
   interface derivedReset = ep7.epDerivedReset;
endmodule
`endif

`ifdef ALTERA
`define ALTERA_TOP
`elsif VSIM
`define ALTERA_TOP
`endif

`ifdef ALTERA_TOP
(* no_default_clock, no_default_reset *)
module mkAlteraPcieHostTop #(Clock clk_100MHz, Clock clk_50MHz, Reset perst_n)(PcieHostTop);

   PcieEndpointS5#(PcieLanes) ep7 <- mkPcieEndpointS5(clk_100MHz, clk_50MHz, perst_n, clocked_by clk_100MHz, reset_by perst_n);

   Clock epPcieClock = ep7.epPcieClock;
   Reset epPcieReset = ep7.epPcieReset;

   Clock portalClock_ = epPcieClock;
   Reset portalReset_ = epPcieReset;

   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(ep7.device, clocked_by portalClock_, reset_by portalReset_);
   mkConnection(ep7.tlp, pciehost.pci, clocked_by portalClock_, reset_by portalReset_);

   interface PcieEndpointS5 tep7 = ep7;
   interface PcieHost tpciehost = pciehost;

   interface Clock pcieClock = epPcieClock;
   interface Reset pcieReset = epPcieReset;
   interface portalClock = portalClock_;
   interface portalReset = portalReset_;
   interface derivedClock = ep7.epDerivedClock;
   interface derivedReset = ep7.epDerivedReset;

endmodule
`endif

`ifdef BSIM
   module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   PcieHostTop _a <- mkBsimPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n); return _a;
   endmodule
`elsif XILINX // XILINX
   //(* synthesize, no_default_clock, no_default_reset *)
   (* no_default_clock, no_default_reset *)
   module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
      PcieHostTop _a <- mkXilinxPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n); return _a;
   endmodule
`elsif ALTERA_TOP
   //(* synthesize, no_default_clock, no_default_reset *)
   (* no_default_clock, no_default_reset *)
   module mkPcieHostTop #(Clock clk_100MHz, Clock clk_50MHz, Reset perst_n)(PcieHostTop);
      PcieHostTop _a <- mkAlteraPcieHostTop(clk_100MHz, clk_50MHz, perst_n); return _a;
   endmodule
`endif // NOT ALTERA


Change mkClockIBUFDS to the Connectal variant

// 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 XilinxCells::*;
import ConnectalXilinxCells::*;
import Gearbox::*;
import Pipe::*;
import FIFO::*;
import BRAMFIFO::*;
import Vector::*;
import Clocks::*;
import DefaultValue::*;

(* always_enabled *)
interface FMComms1ADCPins;
   method Action io_adc_data_p(Bit#(14) v);
   method Action io_adc_data_n(Bit#(14) v);
   method Action io_adc_or_p(Bit#(1) v);
   method Action io_adc_or_n(Bit#(1) v);
   method Action io_adc_dco_p(Bit#(1) v);
   method Action io_adc_dco_n(Bit#(1) v);
   interface Clock deleteme_unused_clock;
   interface Reset deleteme_unused_reset;
endinterface

typedef struct {
   Bit#(14) data_i;
   Bit#(1) z_i;
   Bit#(1) or_i;
   Bit#(14) data_q;
   Bit#(1) z_q;
   Bit#(1) or_q;
   } IQ deriving (Bits);

interface FMComms1ADC;
   interface FMComms1ADCPins pins;
   interface PipeOut#(Bit#(64)) adc;
endinterface

/* This module accepts inputs from an Analog Devices FMComms1
 * evaluation board Analog to Digital Converter, and delivers
 * the data as a PipeOut type on the default clock.
 *
 * Input is double data rate, with clock supplied by the FMComms1
 * Input data is 14 bits twos-complement or offset binary, plus
 * an overrange signa=
 *
 * Differential inputs are converted to single ended by using Xilinx IBUFDS
 * cells. The clock is converted to single ended by an IBUFGDS cell
 *
 * DDR data is convered to SDR using IDDR cells
 * At this point, the data is a 14 bit in-phase data signal, plus in-phase
 * overrange, and a 14 bit quadrature signal, plus overrange.
 *
 * The data is packed into a 64-bit IQ datatype, with overrange as the LSB
 *
 * The 32-bit data is converted to 64-bits by a Gearbox
 *
 * Clock conversion happens 64-bits wide using a SyncBRAMFIFO, which
 * presents a PipeOut channel to the rest of the logic.
 */

module mkFMComms1ADC(FMComms1ADC);

   Clock def_clock <- exposeCurrentClock;
   Reset def_reset <- exposeCurrentReset;

   function Bit#(1) foo(ReadOnly#(Bit#(1)) v);
      return (v._read());
   endfunction

   function ReadOnly#(Bit#(14)) rofromrov(Vector#(14, ReadOnly#(Bit#(1))) v);
      return(interface ReadOnly;
	     method Bit#(14) _read;
		return ( pack(map(foo, v)));
	     endmethod
	     endinterface
	     );
   endfunction

   Clock adc_dco;     /* DDR clock */
   Wire#(Bit#(1)) adc_dco_p <- mkDWire(0);
   Wire#(Bit#(1)) adc_dco_n <- mkDWire(0);
   adc_dco <- mkConnectalClockIBUFDS(adc_dco_p, adc_dco_n);

   Vector#(14, Wire#(Bit#(1))) adc_data_p = newVector;
   for (Integer i = 0; i < 14; i = i + 1)
      adc_data_p[i] <- mkDWire(0, clocked_by adc_dco);

   Vector#(14, Wire#(Bit#(1))) adc_data_n = newVector;
   for (Integer i = 0; i < 14; i = i + 1)
      adc_data_n[i] <- mkDWire(0, clocked_by adc_dco);

   Wire#(Bit#(1)) adc_or_p <- mkDWire(0, clocked_by adc_dco);
   Wire#(Bit#(1)) adc_or_n <- mkDWire(0, clocked_by adc_dco);

   Vector#(14, ReadOnly#(Bit#(1))) v_adc_data;   /* data */
   ReadOnly#(Bit#(14)) adc_data;

   ReadOnly#(Bit#(1)) adc_or;      /* overrange */

   Reset adc_reset <- mkAsyncReset(3, def_reset, adc_dco);
   for(Integer i = 0; i < 14; i = i + 1)
      v_adc_data[i] <- mkIBUFDS(adc_data_p[i], adc_data_n[i], clocked_by adc_dco);
   adc_data = rofromrov(v_adc_data);

   adc_or <- mkIBUFDS(adc_or_p, adc_or_n, clocked_by adc_dco);

   IDDRParams#(Bit#(14)) iddrparams_data = defaultValue;
//   iddrparams_data.ddr_clk_edge = "SAME_EDGE_PIPELINED";
      iddrparams_data.ddr_clk_edge = "SAME_EDGE";
   IDDR#(Bit#(14)) adc_sdr_data <- mkIDDR(iddrparams_data, clocked_by adc_dco);

   IDDRParams#(Bit#(1)) iddrparams_or = defaultValue;
//   iddrparams_or.ddr_clk_edge = "SAME_EDGE_PIPELINED";
   iddrparams_or.ddr_clk_edge = "SAME_EDGE";
   IDDR#(Bit#(1)) adc_sdr_or <- mkIDDR(iddrparams_or, clocked_by adc_dco);

   rule sendup_adc_data;
      adc_sdr_data.d(pack(adc_data));
   endrule

   rule sendup_adc_or;
      adc_sdr_or.d(adc_or);
   endrule

   Gearbox#(1, 2, IQ) gb <- mk1toNGearbox(adc_dco, adc_reset, adc_dco, adc_reset);
   SyncFIFOIfc#(Vector#(2, IQ)) infifo <- mkSyncBRAMFIFO(128, adc_dco, adc_reset, def_clock, def_reset);

   rule sendup_gb_data;
      gb.enq(unpack(pack(IQ{data_i: adc_sdr_data.q1, z_i: 0, or_i: adc_sdr_or.q1,
	 data_q: adc_sdr_data.q2, z_q: 0, or_q: adc_sdr_or.q2})));
   endrule

   rule sendup_adc_fifo_data;
      gb.deq();
      infifo.enq(gb.first());
   endrule

   interface FMComms1ADCPins pins;

      method Action io_adc_data_p(Bit#(14) v);
         for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_p[i] <= v[i];
      endmethod

      method Action io_adc_data_n(Bit#(14) v);
         for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_n[i] <= v[i];
      endmethod

      method Action io_adc_or_p(Bit#(1) v);
	 adc_or_p <= v;
      endmethod

      method Action io_adc_or_n(Bit#(1) v);
	 adc_or_n <= v;
      endmethod
      method Action io_adc_dco_p(Bit#(1) v);
	 adc_dco_p <= v;
      endmethod

      method Action io_adc_dco_n(Bit#(1) v);
	 adc_dco_n <= v;
      endmethod
      interface deleteme_unused_clock = adc_dco;
      interface deleteme_unused_reset = adc_reset;

   endinterface

   interface PipeOut adc;

      method Bit#(64) first();
	 return(unpack(pack(infifo.first)));
      endmethod

      method Action deq() = infifo.deq;

      method Bool notEmpty() = infifo.notEmpty;

   endinterface

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 XilinxCells::*;
import ConnectalXilinxCells::*;
import Gearbox::*;
import Pipe::*;
import FIFO::*;
import BRAMFIFO::*;
import Vector::*;
import Clocks::*;
import DefaultValue::*;

(* always_enabled *)
interface FMComms1ADCPins;
   method Action io_adc_data_p(Bit#(14) v);
   method Action io_adc_data_n(Bit#(14) v);
   method Action io_adc_or_p(Bit#(1) v);
   method Action io_adc_or_n(Bit#(1) v);
   method Action io_adc_dco_p(Bit#(1) v);
   method Action io_adc_dco_n(Bit#(1) v);
   interface Clock deleteme_unused_clock;
   interface Reset deleteme_unused_reset;
endinterface

typedef struct {
   Bit#(14) data_i;
   Bit#(1) z_i;
   Bit#(1) or_i;
   Bit#(14) data_q;
   Bit#(1) z_q;
   Bit#(1) or_q;
   } IQ deriving (Bits);

interface FMComms1ADC;
   interface FMComms1ADCPins pins;
   interface PipeOut#(Bit#(64)) adc;
endinterface

/* This module accepts inputs from an Analog Devices FMComms1
 * evaluation board Analog to Digital Converter, and delivers
 * the data as a PipeOut type on the default clock.
 *
 * Input is double data rate, with clock supplied by the FMComms1
 * Input data is 14 bits twos-complement or offset binary, plus
 * an overrange signa=
 *
 * Differential inputs are converted to single ended by using Xilinx IBUFDS
 * cells. The clock is converted to single ended by an IBUFGDS cell
 *
 * DDR data is convered to SDR using IDDR cells
 * At this point, the data is a 14 bit in-phase data signal, plus in-phase
 * overrange, and a 14 bit quadrature signal, plus overrange.
 *
 * The data is packed into a 64-bit IQ datatype, with overrange as the LSB
 *
 * The 32-bit data is converted to 64-bits by a Gearbox
 *
 * Clock conversion happens 64-bits wide using a SyncBRAMFIFO, which
 * presents a PipeOut channel to the rest of the logic.
 */

module mkFMComms1ADC(FMComms1ADC);

   Clock def_clock <- exposeCurrentClock;
   Reset def_reset <- exposeCurrentReset;

   function Bit#(1) foo(ReadOnly#(Bit#(1)) v);
      return (v._read());
   endfunction

   function ReadOnly#(Bit#(14)) rofromrov(Vector#(14, ReadOnly#(Bit#(1))) v);
      return(interface ReadOnly;
	     method Bit#(14) _read;
		return ( pack(map(foo, v)));
	     endmethod
	     endinterface
	     );
   endfunction

   Clock adc_dco;     /* DDR clock */
   Wire#(Bit#(1)) adc_dco_p <- mkDWire(0);
   Wire#(Bit#(1)) adc_dco_n <- mkDWire(0);
   adc_dco <- mkClockIBUFDS(adc_dco_p, adc_dco_n);

   Vector#(14, Wire#(Bit#(1))) adc_data_p = newVector;
   for (Integer i = 0; i < 14; i = i + 1)
      adc_data_p[i] <- mkDWire(0, clocked_by adc_dco);

   Vector#(14, Wire#(Bit#(1))) adc_data_n = newVector;
   for (Integer i = 0; i < 14; i = i + 1)
      adc_data_n[i] <- mkDWire(0, clocked_by adc_dco);

   Wire#(Bit#(1)) adc_or_p <- mkDWire(0, clocked_by adc_dco);
   Wire#(Bit#(1)) adc_or_n <- mkDWire(0, clocked_by adc_dco);

   Vector#(14, ReadOnly#(Bit#(1))) v_adc_data;   /* data */
   ReadOnly#(Bit#(14)) adc_data;

   ReadOnly#(Bit#(1)) adc_or;      /* overrange */

   Reset adc_reset <- mkAsyncReset(3, def_reset, adc_dco);
   for(Integer i = 0; i < 14; i = i + 1)
      v_adc_data[i] <- mkIBUFDS(adc_data_p[i], adc_data_n[i], clocked_by adc_dco);
   adc_data = rofromrov(v_adc_data);

   adc_or <- mkIBUFDS(adc_or_p, adc_or_n, clocked_by adc_dco);

   IDDRParams#(Bit#(14)) iddrparams_data = defaultValue;
//   iddrparams_data.ddr_clk_edge = "SAME_EDGE_PIPELINED";
      iddrparams_data.ddr_clk_edge = "SAME_EDGE";
   IDDR#(Bit#(14)) adc_sdr_data <- mkIDDR(iddrparams_data, clocked_by adc_dco);

   IDDRParams#(Bit#(1)) iddrparams_or = defaultValue;
//   iddrparams_or.ddr_clk_edge = "SAME_EDGE_PIPELINED";
   iddrparams_or.ddr_clk_edge = "SAME_EDGE";
   IDDR#(Bit#(1)) adc_sdr_or <- mkIDDR(iddrparams_or, clocked_by adc_dco);

   rule sendup_adc_data;
      adc_sdr_data.d(pack(adc_data));
   endrule

   rule sendup_adc_or;
      adc_sdr_or.d(adc_or);
   endrule

   Gearbox#(1, 2, IQ) gb <- mk1toNGearbox(adc_dco, adc_reset, adc_dco, adc_reset);
   SyncFIFOIfc#(Vector#(2, IQ)) infifo <- mkSyncBRAMFIFO(128, adc_dco, adc_reset, def_clock, def_reset);

   rule sendup_gb_data;
      gb.enq(unpack(pack(IQ{data_i: adc_sdr_data.q1, z_i: 0, or_i: adc_sdr_or.q1,
	 data_q: adc_sdr_data.q2, z_q: 0, or_q: adc_sdr_or.q2})));
   endrule

   rule sendup_adc_fifo_data;
      gb.deq();
      infifo.enq(gb.first());
   endrule

   interface FMComms1ADCPins pins;

      method Action io_adc_data_p(Bit#(14) v);
         for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_p[i] <= v[i];
      endmethod

      method Action io_adc_data_n(Bit#(14) v);
         for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_n[i] <= v[i];
      endmethod

      method Action io_adc_or_p(Bit#(1) v);
	 adc_or_p <= v;
      endmethod

      method Action io_adc_or_n(Bit#(1) v);
	 adc_or_n <= v;
      endmethod
      method Action io_adc_dco_p(Bit#(1) v);
	 adc_dco_p <= v;
      endmethod

      method Action io_adc_dco_n(Bit#(1) v);
	 adc_dco_n <= v;
      endmethod
      interface deleteme_unused_clock = adc_dco;
      interface deleteme_unused_reset = adc_reset;

   endinterface

   interface PipeOut adc;

      method Bit#(64) first();
	 return(unpack(pack(infifo.first)));
      endmethod

      method Action deq() = infifo.deq;

      method Bool notEmpty() = infifo.notEmpty;

   endinterface

endmodule


use vec() instead of replicate()

use vec() instead of replicate()

// 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 BuildVector::*;
import GetPut::*;
import ClientServer::*;
import Gearbox::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import MIMO::*;
import Pipe::*;
import Portal::*;
import MemTypes::*;
import ConnectalMemory::*;

interface SharedMemoryPipeOut#(numeric type dataBusWidth, numeric type pipeCount);
   interface SharedMemoryPortalConfig cfg;
   interface Vector#(pipeCount, PipeOut#(Bit#(32))) data;
endinterface
interface SharedMemoryPipeIn#(numeric type dataBusWidth);
   interface SharedMemoryPortalConfig cfg;
   interface PipeIn#(Bit#(32)) data;
endinterface

typedef enum {
   Idle,
   WrPtrRequested, // 1
   RdPtrRequested, // 2
   RequestMessage, // 3
   MessageHeaderRequested, // 4
   MessageRequested, // 5
   Drain,
   UpdateRdPtr,
   UpdateWrPtr,
   UpdateWrPtr2,
   Waiting,
   SendHeader,
   SendMessage,
   SendPadding,
   Stop
   } SharedMemoryPortalState deriving (Bits,Eq);

module mkSharedMemoryRequestPipeOut#(Vector#(2, MemreadServer#(64)) readEngine, Vector#(2, MemwriteServer#(64)) writeEngine)(SharedMemoryPipeOut#(64,pipeCount));
   // read the wrPtr and rdPtr pointers, if they are different, then read a request
   Reg#(Bit#(32)) limitReg <- mkReg(0);
   Reg#(Bit#(32)) wrPtrReg <- mkReg(0);
   Reg#(Bit#(32)) rdPtrReg <- mkReg(0);
   Reg#(Bit#(16)) countReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   MIMOConfiguration mimoConfig = defaultValue;
   MIMO#(2,1,2,Bit#(32)) readMimo <- mkMIMO(mimoConfig);
   Vector#(pipeCount, FIFOF#(Bit#(32))) dataFifo <- replicateM(mkFIFOF);

   let verbose = True;

   rule updateReqWrPtrRdPtr if (state == Idle && readyReg);
      if (verbose) $display("updateReqWrPtrRdPtr");
      readEngine[0].request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= WrPtrRequested;
   endrule

   rule receiveReqWrPtrRdPtr if (state == WrPtrRequested || state == RdPtrRequested);
      let v <- toGet(readEngine[0].data).get();
      let w0 = v.data[31:0];
      let w1 = v.data[63:32];
      let wrPtr = wrPtrReg;
      let rdPtr = rdPtrReg;
      let limit = limitReg;
      if (state == WrPtrRequested) begin
	 limit = w0;
         limitReg <= w0;
         wrPtrReg <= w1;
         wrPtr = w1;
         state <= RdPtrRequested;
      end
      else begin
         if (rdPtrReg == 0) begin
            rdPtr = w0;
            rdPtrReg <= rdPtr;
         end
         if (rdPtr != wrPtrReg)
            state <= RequestMessage;
         else
            state <= Idle;
      end
      if (verbose)
         $display("receiveReqWrPtrRdPtr state=%d w0=%x w1=%x wrPtr=%d rdPtr=%d limit=%d", state, w0, w1, wrPtr, rdPtr, limit);
   endrule

   rule requestMessage if (state == RequestMessage);
      Bit#(32) wordCount = wrPtrReg - rdPtrReg;
      if ((rdPtrReg & 1) == 1) begin
         $display("WARNING requestMessage: reqRdPtr=%d is odd.", rdPtrReg);
      end
      let rdPtr = rdPtrReg + wordCount;
      if (wrPtrReg < rdPtrReg) begin
         $display("requestMessage wrapped: wrPtr=%d rdPtr=%d", wrPtrReg, rdPtrReg);
         wordCount = limitReg - rdPtrReg;
         rdPtr = 4;
      end
      if (verbose) $display("requestMessage id=%d rdPtr=%d wrPtr=%d wordCount=%d", sglIdReg, rdPtrReg, wrPtrReg, wordCount);
      rdPtrReg <= rdPtr;
      countReg <= truncate(wordCount);
      readEngine[1].request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(rdPtrReg << 2), burstLen: 16, len: wordCount << 2, tag: 0});
      state <= MessageHeaderRequested;
   endrule

   let enqCount = 2;
   rule demuxwords if (readMimo.enqReadyN(enqCount));
      let v <- toGet(readEngine[1].data).get();
      Vector#(2,Bit#(32)) dvec = unpack(v.data);
      readMimo.enq(enqCount, dvec);
   endrule

   rule receiveMessageHeader if (state == MessageHeaderRequested);
      let vec <- toGet(toPipeOut(readMimo)).get();
      let hdr = vec[0];
      let methodId = hdr[31:16];
      let messageWords = hdr[15:0];
      methodIdReg <= methodId;
      if (verbose)
         $display("receiveMessageHeader hdr=%x methodId=%x messageWords=%d wordCount=%d", hdr, methodId, messageWords, countReg);
      countReg <= countReg - 1;
      messageWordsReg <= messageWords - 1;
      if (hdr == 0) begin
         if (countReg == 1)
            state <= UpdateRdPtr;
         else
            state <= Drain;
      end
      else if (countReg == 1)
         state <= UpdateRdPtr;
      else if (messageWords == 1)
         state <= MessageHeaderRequested;
      else
         state <= MessageRequested;
   endrule

   rule drain if (state == Drain);
      let vec <- toGet(readMimo).get();
      if (countReg == 1)
         state <= UpdateRdPtr;
      countReg <= countReg - 1;
   endrule

   rule receiveMessage if (state == MessageRequested);
      let vec <- toGet(toPipeOut(readMimo)).get();
      let data = vec[0];
      if (verbose)
         $display("receiveMessage data=%x messageWords=%d wordCount=%d", data, messageWordsReg, countReg);
      if (methodIdReg != 16'hFFFF)
         dataFifo[methodIdReg].enq(data);
      messageWordsReg <= messageWordsReg - 1;
      countReg <= countReg - 1;
      if (countReg <= 1)
         state <= UpdateRdPtr;
      else if (messageWordsReg == 1)
         state <= MessageHeaderRequested;
   endrule

   rule updateRdPtr if (state == UpdateRdPtr);
      if (verbose)
         $display("updateRdPtr: rdPtr=%d", rdPtrReg);
      // update the rdPtr pointer
      writeEngine[0].request.put(
          MemengineCmd {sglId: sglIdReg, base: 8, len: 8, burstLen: 8, tag: 0});
      writeEngine[0].data.enq(extend(rdPtrReg));
      state <= Waiting;
   endrule

   rule waiting if (state == Waiting);
      let done <- writeEngine[0].done.get();
      state <= Idle;
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
	 if (verbose) $display("setSglId id=%d", id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
   interface data = map(toPipeOut, dataFifo);
endmodule

module mkSharedMemoryIndicationPortal#(PipePortal#(numRequests, numIndications, 32) portal,
    Vector#(2,MemReadServer#(64)) readEngine, Vector#(2, MemWriteServer#(64)) writeEngine)(SharedMemoryPortal#(64));
   let defaultClock <- exposeCurrentClock;
   let defaultReset <- exposeCurrentReset;
   // read the wrPtr and rdPtr pointers, if they are different, then read a request
   Reg#(Bit#(16)) limitReg <- mkReg(0);
   Reg#(Bit#(16)) wrPtrReg <- mkReg(0);
   Reg#(Bit#(16)) rdPtrReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(Bool) paddingReg <- mkReg(False);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, portal.indications);
   Bool      interruptStatus = False;
   Bit#(16)  readyChannel = -1;
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Gearbox#(1,2,Bit#(32)) gb <- mk1toNGearbox(defaultClock, defaultReset, defaultClock, defaultReset);

   let verbose = True;

   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule updateIndWrPtrRdPtr if (state == Idle && readyReg);
      readEngine[0].request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= WrPtrRequested;
   endrule

   rule receiveIndWrPtrRdPtr if (state == WrPtrRequested || state == RdPtrRequested);
      let md <- toGet(readEngine[0].data).get();
      let data = md.data;
      let w0 = data[31:0];
      let w1 = data[63:32];
      let wrPtr = wrPtrReg;
      let rdPtr = rdPtrReg;
      if (state == WrPtrRequested) begin
         limitReg <= truncate(w0);
         wrPtrReg <= truncate(w1);
         wrPtr = truncate(w1);
         state <= RdPtrRequested;
      end
      else begin
         if (rdPtrReg == 0) begin
            rdPtr = truncate(w0);
            rdPtrReg <= rdPtr;
         end
         //if (rdPtr != wrPtrReg)
            state <= SendHeader;
         //else
            //state <= Idle;
      end
      if (verbose)
         $display("receiveIndWrPtrRdPtr state=%d w0=%x w1=%x wrPtr=%d rdPtr=%d limit=%d", state, w0, w1, wrPtr, rdPtr, limitReg);
   endrule

   rule send64bits;
      let v = gb.first;
      gb.deq();
      writeEngine[0].data.enq(pack(v));
   endrule

   rule sendHeader if (state == SendHeader && interruptStatus);
      Bit#(16) messageBits = portal.messageSize.size(readyChannel);
      Bit#(16) roundup = messageBits[4:0] == 0 ? 0 : 1;
      Bit#(16) numWords = (messageBits >> 5) + roundup;
      Bit#(16) totalWords = numWords + 1;
      Bit#(32) hdr = extend(readyChannel) << 16 | extend(numWords + 1);
      if (numWords[0] == 0)
         totalWords = numWords + 2;
      paddingReg <= numWords[0] == 0;
      $display("sendHeader hdr=%h messageBits=%d numWords=%d totalWords=%d paddingReg=%d wrPtrReg=%h", hdr, messageBits, numWords, totalWords, paddingReg, wrPtrReg);
      wrPtrReg <= wrPtrReg + totalWords;
      messageWordsReg <= numWords;
      methodIdReg <= readyChannel;
      gb.enq(vec(hdr));
      writeEngine[0].request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(wrPtrReg) << 2, burstLen: 8, len: extend(totalWords) << 2, tag: 0});
      state <= SendMessage;
   endrule

   rule sendMessage if (state == SendMessage);
      messageWordsReg <= messageWordsReg - 1;
      let v = portal.indications[methodIdReg].first;
      portal.indications[methodIdReg].deq();
      gb.enq(vec(v));
      $display("sendMessage v=%h messageWords=%d", v, messageWordsReg);
      if (messageWordsReg == 1) begin
         if (paddingReg)
            state <= SendPadding;
         else
            state <= UpdateWrPtr;
      end
   endrule

   rule sendPadding if (state == SendPadding);
      $display("sendPadding");
      gb.enq(vec(32'hffff0001));
      state <= UpdateWrPtr;
   endrule

   rule updateWrPtr if (state == UpdateWrPtr);
      $display("updateIndWrPtr limit=%d wrPtr=%d", limitReg, wrPtrReg);
      gb.enq(vec(extend(limitReg)));
      writeEngine[0].request.put(
             MemengineCmd {sglId: sglIdReg, base: 0 << 2, burstLen: 8, len: 2 << 2, tag: 0});
      state <= UpdateWrPtr2;
   endrule

   rule updateWrPtr2 if (state == UpdateWrPtr2);
      $display("updateIndWrPtr2");
      gb.enq(vec(extend(wrPtrReg)));
      state <= SendHeader;
   endrule

   rule done;
      let done <- writeEngine[0].done.get();
   endrule
   rule done2;
      let done <- writeEngine[1].done.get();
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
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 GetPut::*;
import ClientServer::*;
import Gearbox::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import MIMO::*;
import Pipe::*;
import Portal::*;
import MemTypes::*;
import ConnectalMemory::*;

interface SharedMemoryPipeOut#(numeric type dataBusWidth, numeric type pipeCount);
   interface SharedMemoryPortalConfig cfg;
   interface Vector#(pipeCount, PipeOut#(Bit#(32))) data;
endinterface
interface SharedMemoryPipeIn#(numeric type dataBusWidth);
   interface SharedMemoryPortalConfig cfg;
   interface PipeIn#(Bit#(32)) data;
endinterface

typedef enum {
   Idle,
   WrPtrRequested, // 1
   RdPtrRequested, // 2
   RequestMessage, // 3
   MessageHeaderRequested, // 4
   MessageRequested, // 5
   Drain,
   UpdateRdPtr,
   UpdateWrPtr,
   UpdateWrPtr2,
   Waiting,
   SendHeader,
   SendMessage,
   SendPadding,
   Stop
   } SharedMemoryPortalState deriving (Bits,Eq);

module mkSharedMemoryRequestPipeOut#(Vector#(2, MemreadServer#(64)) readEngine, Vector#(2, MemwriteServer#(64)) writeEngine)(SharedMemoryPipeOut#(64,pipeCount));
   // read the wrPtr and rdPtr pointers, if they are different, then read a request
   Reg#(Bit#(32)) limitReg <- mkReg(0);
   Reg#(Bit#(32)) wrPtrReg <- mkReg(0);
   Reg#(Bit#(32)) rdPtrReg <- mkReg(0);
   Reg#(Bit#(16)) countReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   MIMOConfiguration mimoConfig = defaultValue;
   MIMO#(2,1,2,Bit#(32)) readMimo <- mkMIMO(mimoConfig);
   Vector#(pipeCount, FIFOF#(Bit#(32))) dataFifo <- replicateM(mkFIFOF);

   let verbose = True;

   rule updateReqWrPtrRdPtr if (state == Idle && readyReg);
      if (verbose) $display("updateReqWrPtrRdPtr");
      readEngine[0].request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= WrPtrRequested;
   endrule

   rule receiveReqWrPtrRdPtr if (state == WrPtrRequested || state == RdPtrRequested);
      let v <- toGet(readEngine[0].data).get();
      let w0 = v.data[31:0];
      let w1 = v.data[63:32];
      let wrPtr = wrPtrReg;
      let rdPtr = rdPtrReg;
      let limit = limitReg;
      if (state == WrPtrRequested) begin
	 limit = w0;
         limitReg <= w0;
         wrPtrReg <= w1;
         wrPtr = w1;
         state <= RdPtrRequested;
      end
      else begin
         if (rdPtrReg == 0) begin
            rdPtr = w0;
            rdPtrReg <= rdPtr;
         end
         if (rdPtr != wrPtrReg)
            state <= RequestMessage;
         else
            state <= Idle;
      end
      if (verbose)
         $display("receiveReqWrPtrRdPtr state=%d w0=%x w1=%x wrPtr=%d rdPtr=%d limit=%d", state, w0, w1, wrPtr, rdPtr, limit);
   endrule

   rule requestMessage if (state == RequestMessage);
      Bit#(32) wordCount = wrPtrReg - rdPtrReg;
      if ((rdPtrReg & 1) == 1) begin
         $display("WARNING requestMessage: reqRdPtr=%d is odd.", rdPtrReg);
      end
      let rdPtr = rdPtrReg + wordCount;
      if (wrPtrReg < rdPtrReg) begin
         $display("requestMessage wrapped: wrPtr=%d rdPtr=%d", wrPtrReg, rdPtrReg);
         wordCount = limitReg - rdPtrReg;
         rdPtr = 4;
      end
      if (verbose) $display("requestMessage id=%d rdPtr=%h wrPtr=%h wordCount=%d", sglIdReg, rdPtrReg, wrPtrReg, wordCount);
      rdPtrReg <= rdPtr;
      countReg <= truncate(wordCount);
      readEngine[1].request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(rdPtrReg << 2), burstLen: 16, len: wordCount << 2, tag: 0});
      state <= MessageHeaderRequested;
   endrule

   let enqCount = 2;
   rule demuxwords if (readMimo.enqReadyN(enqCount));
      let v <- toGet(readEngine[1].data).get();
      Vector#(2,Bit#(32)) dvec = unpack(v.data);
      readMimo.enq(enqCount, dvec);
   endrule

   rule receiveMessageHeader if (state == MessageHeaderRequested);
      let vec <- toGet(toPipeOut(readMimo)).get();
      let hdr = vec[0];
      let methodId = hdr[31:16];
      let messageWords = hdr[15:0];
      methodIdReg <= methodId;
      if (verbose)
         $display("receiveMessageHeader hdr=%x methodId=%x messageWords=%d wordCount=%d", hdr, methodId, messageWords, countReg);
      countReg <= countReg - 1;
      messageWordsReg <= messageWords - 1;
      if (hdr == 0) begin
         if (countReg == 1)
            state <= UpdateRdPtr;
         else
            state <= Drain;
      end
      else if (countReg == 1)
         state <= UpdateRdPtr;
      else if (messageWords == 1)
         state <= MessageHeaderRequested;
      else
         state <= MessageRequested;
   endrule

   rule drain if (state == Drain);
      let vec <- toGet(readMimo).get();
      if (countReg == 1)
         state <= UpdateRdPtr;
      countReg <= countReg - 1;
   endrule

   rule receiveMessage if (state == MessageRequested);
      let vec <- toGet(toPipeOut(readMimo)).get();
      let data = vec[0];
      if (verbose)
         $display("receiveMessage data=%x messageWords=%d wordCount=%d", data, messageWordsReg, countReg);
      if (methodIdReg != 16'hFFFF)
         dataFifo[methodIdReg].enq(data);
      messageWordsReg <= messageWordsReg - 1;
      countReg <= countReg - 1;
      if (countReg <= 1)
         state <= UpdateRdPtr;
      else if (messageWordsReg == 1)
         state <= MessageHeaderRequested;
   endrule

   rule updateRdPtr if (state == UpdateRdPtr);
      if (verbose)
         $display("updateRdPtr: rdPtr=%d", rdPtrReg);
      // update the rdPtr pointer
      writeEngine[0].request.put(
          MemengineCmd {sglId: sglIdReg, base: 8, len: 8, burstLen: 8, tag: 0});
      writeEngine[0].data.enq(extend(rdPtrReg));
      state <= Waiting;
   endrule

   rule waiting if (state == Waiting);
      let done <- writeEngine[0].done.get();
      state <= Idle;
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
	 if (verbose) $display("setSglId id=%d", id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
   interface data = map(toPipeOut, dataFifo);
endmodule

module mkSharedMemoryIndicationPortal#(PipePortal#(numRequests, numIndications, 32) portal,
    Vector#(2,MemReadServer#(64)) readEngine, Vector#(2, MemWriteServer#(64)) writeEngine)(SharedMemoryPortal#(64));
   let defaultClock <- exposeCurrentClock;
   let defaultReset <- exposeCurrentReset;
   // read the wrPtr and rdPtr pointers, if they are different, then read a request
   Reg#(Bit#(16)) limitReg <- mkReg(0);
   Reg#(Bit#(16)) wrPtrReg <- mkReg(0);
   Reg#(Bit#(16)) rdPtrReg <- mkReg(0);
   Reg#(Bit#(16)) messageWordsReg <- mkReg(0);
   Reg#(Bit#(16)) methodIdReg <- mkReg(0);
   Reg#(Bool) paddingReg <- mkReg(False);
   Reg#(SharedMemoryPortalState) state <- mkReg(Idle);
   Reg#(Bit#(32)) sglIdReg <- mkReg(0);
   Reg#(Bool)     readyReg   <- mkReg(False);
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, portal.indications);
   Bool      interruptStatus = False;
   Bit#(16)  readyChannel = -1;
   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Gearbox#(1,2,Bit#(32)) gb <- mk1toNGearbox(defaultClock, defaultReset, defaultClock, defaultReset);

   let verbose = True;

   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule updateIndWrPtrRdPtr if (state == Idle && readyReg);
      readEngine[0].request.put(
          MemengineCmd {sglId: sglIdReg, base: 0, burstLen: 16, len: 16, tag: 0});
      state <= WrPtrRequested;
   endrule

   rule receiveIndWrPtrRdPtr if (state == WrPtrRequested || state == RdPtrRequested);
      let md <- toGet(readEngine[0].data).get();
      let data = md.data;
      let w0 = data[31:0];
      let w1 = data[63:32];
      let wrPtr = wrPtrReg;
      let rdPtr = rdPtrReg;
      if (state == WrPtrRequested) begin
         limitReg <= truncate(w0);
         wrPtrReg <= truncate(w1);
         wrPtr = truncate(w1);
         state <= RdPtrRequested;
      end
      else begin
         if (rdPtrReg == 0) begin
            rdPtr = truncate(w0);
            rdPtrReg <= rdPtr;
         end
         //if (rdPtr != wrPtrReg)
            state <= SendHeader;
         //else
            //state <= Idle;
      end
      if (verbose)
         $display("receiveIndWrPtrRdPtr state=%d w0=%x w1=%x wrPtr=%d rdPtr=%d limit=%d", state, w0, w1, wrPtr, rdPtr, limitReg);
   endrule

   rule send64bits;
      let v = gb.first;
      gb.deq();
      writeEngine[0].data.enq(pack(v));
   endrule

   rule sendHeader if (state == SendHeader && interruptStatus);
      Bit#(16) messageBits = portal.messageSize.size(readyChannel);
      Bit#(16) roundup = messageBits[4:0] == 0 ? 0 : 1;
      Bit#(16) numWords = (messageBits >> 5) + roundup;
      Bit#(16) totalWords = numWords + 1;
      Bit#(32) hdr = extend(readyChannel) << 16 | extend(numWords + 1);
      if (numWords[0] == 0)
         totalWords = numWords + 2;
      paddingReg <= numWords[0] == 0;
      $display("sendHeader hdr=%h messageBits=%d numWords=%d totalWords=%d paddingReg=%d wrPtrReg=%h", hdr, messageBits, numWords, totalWords, paddingReg, wrPtrReg);
      wrPtrReg <= wrPtrReg + totalWords;
      messageWordsReg <= numWords;
      methodIdReg <= readyChannel;
      gb.enq(replicate(hdr));
      writeEngine[0].request.put( MemengineCmd
          {sglId: sglIdReg, base: extend(wrPtrReg) << 2, burstLen: 8, len: extend(totalWords) << 2, tag: 0});
      state <= SendMessage;
   endrule

   rule sendMessage if (state == SendMessage);
      messageWordsReg <= messageWordsReg - 1;
      let v = portal.indications[methodIdReg].first;
      portal.indications[methodIdReg].deq();
      gb.enq(replicate(v));
      $display("sendMessage v=%h messageWords=%d", v, messageWordsReg);
      if (messageWordsReg == 1) begin
         if (paddingReg)
            state <= SendPadding;
         else
            state <= UpdateWrPtr;
      end
   endrule

   rule sendPadding if (state == SendPadding);
      $display("sendPadding");
      gb.enq(replicate(32'hffff0001));
      state <= UpdateWrPtr;
   endrule

   rule updateWrPtr if (state == UpdateWrPtr);
      $display("updateIndWrPtr limit=%d wrPtr=%d", limitReg, wrPtrReg);
      gb.enq(replicate(extend(limitReg)));
      writeEngine[0].request.put(
             MemengineCmd {sglId: sglIdReg, base: 0 << 2, burstLen: 8, len: 2 << 2, tag: 0});
      state <= UpdateWrPtr2;
   endrule

   rule updateWrPtr2 if (state == UpdateWrPtr2);
      $display("updateIndWrPtr2");
      gb.enq(replicate(extend(wrPtrReg)));
      state <= SendHeader;
   endrule

   rule done;
      let done <- writeEngine[0].done.get();
   endrule
   rule done2;
      let done <- writeEngine[1].done.get();
   endrule

   interface SharedMemoryPortalConfig cfg;
      method Action setSglId(Bit#(32) id);
         sglIdReg <= id;
         readyReg <= True;
      endmethod
   endinterface
endmodule