fixed a scheduling problem in mkDotProd

fixed a scheduling problem in mkDotProd

// 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 FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import DmaVector::*;
import PortalMemory::*;
import Dma::*;
import FloatingPoint::*;
import Pipe::*;
import FloatOps::*;

module [Module] mkDotProd#(PipeOut#(Vector#(n,Float)) xpipe, PipeOut#(Vector#(n,Float)) ypipe, UInt#(nwidth) numElts)(PipeOut#(Float))
   provisos (
      Add#(1,a__,n)
      );

   Bool verbose = True;

   PipeOut#(Tuple2#(Vector#(n,Float),Vector#(n,Float))) xypipe <- mkJoin(tuple2, xpipe, ypipe);

   Vector#(n, Server#(Tuple4#(Maybe#(Float), Float, Float, RoundMode), Tuple2#(Float,Exception))) macs <- replicateM(mkFloatMac);
   Vector#(n, FIFO#(Maybe#(Float))) accumFifo <- replicateM(mkFIFO());
   Reg#(UInt#(nwidth)) countInReg <- mkReg(0);
   Reg#(UInt#(nwidth)) countOutReg <- mkReg(0);
   FIFOF#(Float) resultFifo <- mkFIFOF();

   rule mul;
      let v = xypipe.first;
      xypipe.deq;
      let x = tpl_1(v);
      let y = tpl_2(v);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 Maybe#(Float) accum = tagged Invalid;
	 if (countInReg > 0) begin
	    accum = accumFifo[i].first();
	    accumFifo[i].deq();
	 end
	 if (verbose) $display($format(fshow(" dotprod x=") + fshow(x) + fshow(" y=") + fshow(y) + fshow(" accum=")+fshow(pack(accum))));
         macs[i].request.put(tuple4(accum, x[i], y[i], defaultValue));
	 let c = countInReg + 1;
	 if (c == numElts)
	    c = 0;
	 countInReg <= c;
      end
   endrule

   rule macout;
      Vector#(n,Float) vs;
      let c = countOutReg + 1;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 let resp <- macs[i].response.get();
	 vs[i] = tpl_1(resp);
	 if (c < numElts) begin
	    accumFifo[i].enq(tagged Valid tpl_1(resp));
	 end
	 else begin
	    // FIXME need to fold the values together, but we're only compiling for n == 1
	    $display("resultFifo.enq %h", tpl_1(resp));
	    if (i == 0) begin
	       resultFifo.enq(tpl_1(resp));
	    end
	 end
      end
      if (c == numElts)
	 c = 0;
      countOutReg <= c;
      if (verbose) $display(fshow("countOutReg=")+fshow(countOutReg)+fshow(" numElts=")+fshow(numElts)+fshow(" mul=") + fshow(vs));
   endrule

   PipeOut#(Float) dotpipe = toPipeOut(resultFifo);
   return dotpipe;
endmodule

typedef struct {
   a xbase;
   a xlimit;
   a xstep;
   a ybase;
   a ylimit;
   a ystep;
} XYRangeConfig#(type a) deriving (Bits, FShow);

interface XYRangePipeIfc#(type a);
   interface PipeOut#(Tuple2#(a,a)) pipe;
   method Action start(XYRangeConfig#(a) cfg);
   method Action display();
endinterface

module mkXYRangePipeOut(XYRangePipeIfc#(a)) provisos (Arith#(a), Bits#(a,awidth), Eq#(a), Ord#(a));
   Reg#(a) x <- mkReg(0);
   Reg#(a) y <- mkReg(0);
   Reg#(a) xbase <- mkReg(0);
   Reg#(a) ybase <- mkReg(0);
   Reg#(a) xstep <- mkReg(0);
   Reg#(a) ystep <- mkReg(0);
   Reg#(a) xlimit <- mkReg(0);
   Reg#(a) ylimit <- mkReg(0);

   interface PipeOut pipe;
      method Tuple2#(a,a) first() if (x < xlimit && y < ylimit);
	 return tuple2(x,y);
      endmethod
      method Action deq if (x < xlimit && y < ylimit);
	 let newx = x;
	 let newy = y+ystep;
	 if (newy >= ylimit && x < xlimit) begin
	    newy = ybase;
	    newx = newx + xstep;
	 end
	 x <= newx;
	 y <= newy;
      endmethod
      method Bool notEmpty();
	 return (x < xlimit && y < ylimit);
      endmethod
   endinterface
   method Action start(XYRangeConfig#(a) cfg) if (x >= xlimit);
      x <= cfg.xbase;
      y <= cfg.ybase;
      xbase <= cfg.xbase;
      ybase <= cfg.ybase;
      xstep <= cfg.xstep;
      ystep <= cfg.ystep;
      xlimit <= cfg.xlimit;
      ylimit <= cfg.ylimit;
   endmethod
   method Action display();
   	 $display("XYRangePipe x=%d xlimit=%d y=%d ylimit=%d", x, xlimit, y, ylimit);
   endmethod
endmodule: mkXYRangePipeOut

typedef struct {
   DmaPointer pointer;
   addrtype base;
   addrtype numRows;
   addrtype numColumns;
} MatrixDescriptor#(type addrtype) deriving (Bits);

// row major layout
interface DmaMatrixMultiplyIfc#(numeric type addrwidth, numeric type dsz);
   interface DmaWriteClient#(dsz) dmaClient;
   method Action start(DmaPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       DmaPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       DmaPointer pointerC);
   interface PipeOut#(Bool) pipe;
endinterface

typedef enum {
   Idle, Ready, Running, Done
   } MMState deriving (Bits, Eq);

module [Module] mkDmaMatrixMultiply#(Vector#(1, VectorSource#(dsz, Vector#(1, Float))) sourceA,
				     Vector#(k, VectorSource#(dsz, Vector#(1, Float))) sourceB,
				     function Module#(DmaVectorSink#(dsz, Vector#(1, Float))) mkSink(PipeOut#(Vector#(1, Float)) pipe_in)
				     )(DmaMatrixMultiplyIfc#(addrwidth, dsz))
   provisos (Add#(a__,DmaOffsetSize,addrwidth)
	     , Add#(1,0,n)
	     , Add#(1,c__,k)
	     , FShow#(Float)
	     , Arith#(Float)
	     , Bits#(Vector#(1, Float), dsz));

   let n = valueOf(n);
   let k = valueOf(k);
   Bool verbose = True;

   Reg#(Bool) doneReg <- mkReg(False);
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorA <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorB <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorC <- mkReg(unpack(0));
   Reg#(UInt#(addrwidth)) dpCount <- mkReg(0);

   Vector#(k, PipeOut#(Vector#(1,Float))) aPipes <- mkForkVector(sourceA[0].pipe);

   function Module#(PipeOut#(Float)) mkFxDotProd(Integer i);
      return mkDotProd(aPipes[i], sourceB[i].pipe, descriptorA.numColumns/fromInteger(n));
   endfunction
   Vector#(n, PipeOut#(Float)) fxdotprods <- genWithM(mkFxDotProd);

   FIFOF#(Vector#(n,Float)) dfifo <- mkFIFOF();
   let sinkC <- mkSink(toPipeOut(dfifo));

   XYRangePipeIfc#(UInt#(addrwidth)) xypipeifc <- mkXYRangePipeOut();

   Vector#(TAdd#(n,1), PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth)))) xypipes <- mkForkVector(xypipeifc.pipe);

   Reg#(Bool) running <- mkReg(False);
   FIFOF#(Bool) doneFifo <- mkFIFOF();

   for (Integer i = 0; i < k; i = i + 1) begin
      rule startDotProd;
	  Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[i].first;
	  xypipes[i].deq();

	  let row = tpl_1(xy);
	  let col = tpl_2(xy)+fromInteger(i);

	  if (verbose) $display($format(fshow("startDotProd xy=")+fshow(tuple2(row,col))));
	  let startA = row*descriptorA.numColumns/fromInteger(n); // row major
	  let startB = col*descriptorB.numColumns/fromInteger(n); // col major layout (pre-transposed)
	  let startC = (row*descriptorC.numColumns + col) / fromInteger(n); // row major
	  if (verbose) $display($format(fshow("startDotProd xy=")+fshow(tuple2(row,col))
					+fshow(" colsC=")+fshow(descriptorC.numColumns)
					+fshow(" startC=")+fshow(startC)));

	  if (i == 0)
	     sourceA[0].start(descriptorA.pointer, pack(truncate(startA)), pack(truncate(startA + descriptorA.numColumns/fromInteger(n))));
	  sourceB[i].start(descriptorB.pointer, pack(truncate(startB)), pack(truncate(startB + descriptorB.numColumns/fromInteger(n))));
	  if (i == 0)
	     sinkC.vector.start(descriptorC.pointer, pack(truncate(startC)), pack(truncate(startC + fromInteger(k))));
       endrule
   end

   rule dotProdValue;
      Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[n].first;
      xypipes[n].deq;
      Vector#(n,Float) vs;
      for (Integer i = 0; i < k; i = i + 1) begin
	 let v = fxdotprods[i].first;
	 fxdotprods[i].deq;
	 let xyi = tuple2(tpl_1(xy), tpl_2(xy)+fromInteger(i));
	 if (verbose) $display($format(fshow("dotprodvalue xy=")+fshow(xyi)+fshow(" dotprod=")+fshow(v)));
	 vs[i] = v;
      end
      dfifo.enq(vs);
   endrule

   rule sinkDone;
      // each time we write a burst of k values via sinkC
      sinkC.vector.pipe.deq();
      let c = dpCount-fromInteger(k);
      dpCount <= c;
      if (c == 0) begin
	 running <= False;
	 doneFifo.enq(?);
      end
   endrule

   method Action start(DmaPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       DmaPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       DmaPointer pointerC) if (dpCount == 0);
      XYRangeConfig#(UInt#(addrwidth)) xycfg = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
							      ybase: 0, ylimit: numRowsB, ystep: fromInteger(n) };
      descriptorA <= MatrixDescriptor { pointer: pointerA, base: 0, numRows: numRowsA, numColumns: numColumnsA};
      descriptorB <= MatrixDescriptor { pointer: pointerB, base: 0, numRows: numRowsB, numColumns: numColumnsB};
      descriptorC <= MatrixDescriptor { pointer: pointerC, base: 0, numRows: numRowsA, numColumns: numRowsB};
      dpCount <= numRowsA*numRowsB;

      $display("mm pointerA=%d pointerB=%d pointerC=%d\n", pointerA, pointerB, pointerC);
      if (verbose) $display("mm.start ra=%d ca=%d rb=%d cb=%d dpCount=%d", numRowsA, numColumnsA, numRowsB, numColumnsB, dpCount);
      if (verbose) $display($format(fshow("mm.start ")+fshow(xycfg)));
      xypipeifc.start(xycfg);
   endmethod

   interface DmaWriteClient dmaClient = sinkC.dmaClient;
   interface PipeOut pipe = toPipeOut(doneFifo);
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 FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import DmaVector::*;
import PortalMemory::*;
import Dma::*;
import FloatingPoint::*;
import Pipe::*;
import FloatOps::*;

module [Module] mkDotProd#(PipeOut#(Vector#(n,Float)) xpipe, PipeOut#(Vector#(n,Float)) ypipe, UInt#(nwidth) numElts)(PipeOut#(Float))
   provisos (
      Add#(1,a__,n)
      );

   Bool verbose = True;

   PipeOut#(Tuple2#(Vector#(n,Float),Vector#(n,Float))) xypipe <- mkJoin(tuple2, xpipe, ypipe);

   Vector#(n, Server#(Tuple4#(Maybe#(Float), Float, Float, RoundMode), Tuple2#(Float,Exception))) macs <- replicateM(mkFloatMac);
   Vector#(n, FIFO#(Maybe#(Float))) accumFifo <- replicateM(mkFIFO());
   Reg#(UInt#(nwidth)) countMulReg <- mkReg(0);
   FIFOF#(Float) resultFifo <- mkFIFOF();

   rule mul if (countMulReg < numElts);
      let v = xypipe.first;
      xypipe.deq;
      let x = tpl_1(v);
      let y = tpl_2(v);
      if (verbose) $display($format(fshow("countMulReg=")+fshow(countMulReg)+fshow(" dotprod x=") + fshow(x) + fshow(" y=") + fshow(y)));

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	  Maybe#(Float) accum = tagged Invalid;
	  if (countMulReg > 0) begin
	     accum = accumFifo[i].first();
	     accumFifo[i].deq();
	  end
         macs[i].request.put(tuple4(accum, x[i], y[i], defaultValue));
      end
      countMulReg <= countMulReg + 1;
   endrule

   rule macout;
      Vector#(n,Float) vs;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 let resp <- macs[i].response.get();
	 vs[i] = tpl_1(resp);
	 if (countMulReg < numElts) begin
	    accumFifo[i].enq(tagged Valid tpl_1(resp));
	 end
	 else begin
	    // FIXME need to fold the values together, but we're only compiling for n == 1
	    $display("resultFifo.enq %h", tpl_1(resp));
	    if (i == 0) begin
	       countMulReg <= 0;
	       resultFifo.enq(tpl_1(resp));
	    end
	 end
      end
      if (verbose) $display(fshow("countMulReg=")+fshow(countMulReg)+fshow(" numElts=")+fshow(numElts)+fshow(" mul=") + fshow(vs));
   endrule

   PipeOut#(Float) dotpipe = toPipeOut(resultFifo);
   return dotpipe;
endmodule

typedef struct {
   a xbase;
   a xlimit;
   a xstep;
   a ybase;
   a ylimit;
   a ystep;
} XYRangeConfig#(type a) deriving (Bits, FShow);

interface XYRangePipeIfc#(type a);
   interface PipeOut#(Tuple2#(a,a)) pipe;
   method Action start(XYRangeConfig#(a) cfg);
   method Action display();
endinterface

module mkXYRangePipeOut(XYRangePipeIfc#(a)) provisos (Arith#(a), Bits#(a,awidth), Eq#(a), Ord#(a));
   Reg#(a) x <- mkReg(0);
   Reg#(a) y <- mkReg(0);
   Reg#(a) xbase <- mkReg(0);
   Reg#(a) ybase <- mkReg(0);
   Reg#(a) xstep <- mkReg(0);
   Reg#(a) ystep <- mkReg(0);
   Reg#(a) xlimit <- mkReg(0);
   Reg#(a) ylimit <- mkReg(0);

   interface PipeOut pipe;
      method Tuple2#(a,a) first() if (x < xlimit && y < ylimit);
	 return tuple2(x,y);
      endmethod
      method Action deq if (x < xlimit && y < ylimit);
	 let newx = x;
	 let newy = y+ystep;
	 if (newy >= ylimit && x < xlimit) begin
	    newy = ybase;
	    newx = newx + xstep;
	 end
	 x <= newx;
	 y <= newy;
      endmethod
      method Bool notEmpty();
	 return (x < xlimit && y < ylimit);
      endmethod
   endinterface
   method Action start(XYRangeConfig#(a) cfg) if (x >= xlimit);
      x <= cfg.xbase;
      y <= cfg.ybase;
      xbase <= cfg.xbase;
      ybase <= cfg.ybase;
      xstep <= cfg.xstep;
      ystep <= cfg.ystep;
      xlimit <= cfg.xlimit;
      ylimit <= cfg.ylimit;
   endmethod
   method Action display();
   	 $display("XYRangePipe x=%d xlimit=%d y=%d ylimit=%d", x, xlimit, y, ylimit);
   endmethod
endmodule: mkXYRangePipeOut

typedef struct {
   DmaPointer pointer;
   addrtype base;
   addrtype numRows;
   addrtype numColumns;
} MatrixDescriptor#(type addrtype) deriving (Bits);

// row major layout
interface DmaMatrixMultiplyIfc#(numeric type addrwidth, numeric type dsz);
   interface DmaWriteClient#(dsz) dmaClient;
   method Action start(DmaPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       DmaPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       DmaPointer pointerC);
   interface PipeOut#(Bool) pipe;
endinterface

typedef enum {
   Idle, Ready, Running, Done
   } MMState deriving (Bits, Eq);

module [Module] mkDmaMatrixMultiply#(Vector#(1, VectorSource#(dsz, Vector#(1, Float))) sourceA,
				     Vector#(k, VectorSource#(dsz, Vector#(1, Float))) sourceB,
				     function Module#(DmaVectorSink#(dsz, Vector#(1, Float))) mkSink(PipeOut#(Vector#(1, Float)) pipe_in)
				     )(DmaMatrixMultiplyIfc#(addrwidth, dsz))
   provisos (Add#(a__,DmaOffsetSize,addrwidth)
	     , Add#(1,0,n)
	     , Add#(1,c__,k)
	     , FShow#(Float)
	     , Arith#(Float)
	     , Bits#(Vector#(1, Float), dsz));

   let n = valueOf(n);
   let k = valueOf(k);
   Bool verbose = True;

   Reg#(Bool) doneReg <- mkReg(False);
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorA <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorB <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorC <- mkReg(unpack(0));
   Reg#(UInt#(addrwidth)) dpCount <- mkReg(0);

   Vector#(k, PipeOut#(Vector#(1,Float))) aPipes <- mkForkVector(sourceA[0].pipe);

   function Module#(PipeOut#(Float)) mkFxDotProd(Integer i);
      return mkDotProd(aPipes[i], sourceB[i].pipe, descriptorA.numColumns/fromInteger(n));
   endfunction
   Vector#(n, PipeOut#(Float)) fxdotprods <- genWithM(mkFxDotProd);

   FIFOF#(Vector#(n,Float)) dfifo <- mkFIFOF();
   let sinkC <- mkSink(toPipeOut(dfifo));

   XYRangePipeIfc#(UInt#(addrwidth)) xypipeifc <- mkXYRangePipeOut();

   Vector#(TAdd#(n,1), PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth)))) xypipes <- mkForkVector(xypipeifc.pipe);

   Reg#(Bool) running <- mkReg(False);
   FIFOF#(Bool) doneFifo <- mkFIFOF();

   for (Integer i = 0; i < k; i = i + 1) begin
      rule startDotProd;
	  Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[i].first;
	  xypipes[i].deq();

	  let row = tpl_1(xy);
	  let col = tpl_2(xy)+fromInteger(i);

	  if (verbose) $display($format(fshow("startDotProd xy=")+fshow(tuple2(row,col))));
	  let startA = row*descriptorA.numColumns/fromInteger(n); // row major
	  let startB = col*descriptorB.numColumns/fromInteger(n); // col major layout (pre-transposed)
	  let startC = (row*descriptorC.numColumns + col) / fromInteger(n); // row major
	  if (verbose) $display($format(fshow("startDotProd xy=")+fshow(tuple2(row,col))
					+fshow(" colsC=")+fshow(descriptorC.numColumns)
					+fshow(" startC=")+fshow(startC)));

	  if (i == 0)
	     sourceA[0].start(descriptorA.pointer, pack(truncate(startA)), pack(truncate(startA + descriptorA.numColumns/fromInteger(n))));
	  sourceB[i].start(descriptorB.pointer, pack(truncate(startB)), pack(truncate(startB + descriptorB.numColumns/fromInteger(n))));
	  if (i == 0)
	     sinkC.vector.start(descriptorC.pointer, pack(truncate(startC)), pack(truncate(startC + fromInteger(k))));
       endrule
   end

   rule dotProdValue;
      Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[n].first;
      xypipes[n].deq;
      Vector#(n,Float) vs;
      for (Integer i = 0; i < k; i = i + 1) begin
	 let v = fxdotprods[i].first;
	 fxdotprods[i].deq;
	 let xyi = tuple2(tpl_1(xy), tpl_2(xy)+fromInteger(i));
	 if (verbose) $display($format(fshow("dotprodvalue xy=")+fshow(xyi)+fshow(" dotprod=")+fshow(v)));
	 vs[i] = v;
      end
      dfifo.enq(vs);
   endrule

   rule sinkDone;
      // each time we write a burst of k values via sinkC
      sinkC.vector.pipe.deq();
      let c = dpCount-fromInteger(k);
      dpCount <= c;
      if (c == 0) begin
	 running <= False;
	 doneFifo.enq(?);
      end
   endrule

   method Action start(DmaPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       DmaPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       DmaPointer pointerC) if (dpCount == 0);
      XYRangeConfig#(UInt#(addrwidth)) xycfg = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
							      ybase: 0, ylimit: numRowsB, ystep: fromInteger(n) };
      descriptorA <= MatrixDescriptor { pointer: pointerA, base: 0, numRows: numRowsA, numColumns: numColumnsA};
      descriptorB <= MatrixDescriptor { pointer: pointerB, base: 0, numRows: numRowsB, numColumns: numColumnsB};
      descriptorC <= MatrixDescriptor { pointer: pointerC, base: 0, numRows: numRowsA, numColumns: numRowsB};
      dpCount <= numRowsA*numRowsB;

      $display("mm pointerA=%d pointerB=%d pointerC=%d\n", pointerA, pointerB, pointerC);
      if (verbose) $display("mm.start ra=%d ca=%d rb=%d cb=%d dpCount=%d", numRowsA, numColumnsA, numRowsB, numColumnsB, dpCount);
      if (verbose) $display($format(fshow("mm.start ")+fshow(xycfg)));
      xypipeifc.start(xycfg);
   endmethod

   interface DmaWriteClient dmaClient = sinkC.dmaClient;
   interface PipeOut pipe = toPipeOut(doneFifo);
endmodule


pass size of mkMIFO through to mkSizedFIFOF

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

   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

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


swap master and slave in the interface

swap master and slave in the interface

// Copyright (c) 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.

// This file is a hand-generated file that we hope will someday be
// generated automatically by connectal/generated/scripts/importbvi.py
//
// Created by copying the style of connectal/generated/xilinx/PPS7LIB.bsv

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;
import AxiBits::*;

// The name of this interface is a prefix "Par_" plus the common prefix of the signals "txo"
// Hopefully this is what importbvi.py would do
interface Par_txo;
   method Action data_p(Bit#(8) v);
   method Action data_n(Bit#(8) v);
   method Action frame_p(Bit#(1) v);
   method Action frame_n(Bit#(1) v);
   method Action lclk_p(Bit#(1) v);
   method Action lclk_n(Bit#(1) v);
endinterface

interface Par_txi;
   method Bit#(1) wr_wait_p();
   method Bit#(1) wr_wait_n();
   method Bit#(1) rd_wait_p();
   method Bit#(1) rd_wait_n();
endinterface

interface Par_rxi;
   method Bit#(8) data_p();
   method Bit#(8) data_n();
   method Bit#(1) frame_p();
   method Bit#(1) frame_n();
   method Bit#(1) lclk_p();
   method Bit#(1) lclk_n();
   method Action cclk_p(Bit#(1));
   method Action cclk_n(Bit#(1));
endinterface

interface Par_rxo;
   method Action wr_wait_p(Bit#(1) v);
   method Action wr_wait_n(Bit#(1) v);
   method Action rd_wait_p(Bit#(1) v);
   method Action rd_wait_n(Bit#(1) v);
endinterface

interface Par_misc;
   method Bit#(1) cactive();
   method Bit#(1) csysack();
   method Action reset_chip();
   method Action reset_fpga();
endinterface

interface PParallellaLib;
   interface Par_txo txo;
   interface Par_txi txi;
   interface Par_rxo rxo;
   interface Par_rxi rxi;
   interface AxiSlaveCommon#(32,32,12) maxi;   // this will connect to a master
   interface AxiMasterCommon#(32,64, 6) saxi;  // this will connect to a slave
   interface Par_misc misc;
endinterface;

module mkPParallellaLIB#(Clock maxiclk, Clock saxiclk,
   Reset maxiclk_reset, Reset saxiclk_reset,\
   Reset maxireset, Reset saxireset,
   Reset reset_chip, Reset reset_fpga)(PParallellaLib);
   default_clock clk();
   default_reset rst();
   input_clock maxiclk(emaxi_aclk) = maxiclk;  // assigns the verilog emaxi_aclk
   input_clock saxiclk(esaxi_aclk) = saxiclk;  // assigns the verilog esaxi_aclk
   input_reset maxiclk_reset() = maxiclk_reset; /* from clock*/
   input_reset saxiclk_reset() = saxiclk_reset; /* from clock*/

   interface Par_misc;
   method cactive(cactive);
   method csysack(csysack);
   method reset_chip(reset_chip) enable((*inhigh*) EN_reset_chip);
   method reset_fpga(reset_fpga) enable((*inhigh*) EN_reset_fpga);
   endinterface

   interface Par_txo;
      method data_p(txo_data_p) enable((*inhigh*) EN_txo_data_p);
      method data_n(txo_data_n) enable((*inhigh*) EN_txo_data_n);
      method frame_p(txo_frame_p) enable((*inhigh*) EN_txo_frame_p);
      method frame_n(txo_frame_n) enable((*inhigh*) EN_txo_frame_n);
   endinterface

   interface Par_txi;
      method txo_wr_wait_p wr_wait_p();
      method txo_wr_wait_n wr_wait_n();
      method txo_rd_wait_p rd_wait_p();
      method txo_rd_wait_n rd_wait_n();
   endinterface

   interface Par_rxi;
      method rxi_data_p data_p();
      method rxi_data_n data_n();
      method rxi_frame_p frame_p();
      method rxi_frame_n frame_n();
   endinterface

   interface Par_rxo;
      method wr_wait_p(rxo_wr_wait_p) enable((*inhigh*) EN_rxo_wr_wait_p);
      method wr_wait_n(rxo_wr_wait_n) enable((*inhigh*) EN_rxo_wr_wait_n);
      method rd_wait_p(rxo_rd_wait_p) enable((*inhigh*) EN_rxo_rd_wait_p);
      method rd_wait_n(rxo_rd_wait_n) enable((*inhigh*) EN_rxo_rd_wait_n);
      method cclk_p(rxi_cclk_p) enable((*inhigh*) EN_rxi_cclk_p);
      method cclk_n(rxi_cclk_n) enable((*inhigh*) EN_rxi_cclk_p);
   endinterface

   interface Par_emaxi;
      method emaxi_araddr araddr() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arburst arburst() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arcache arcache() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_aresetn aresetn() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arid arid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arlen arlen() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arlock arlock() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arprot arprot() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arqos arqos() clocked_by (maxiclk) reset_by(maxireset);
      method arready(emaxi_arready)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_arready);
      method emaxi_arsize arsize() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arvalid arvalid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awaddr awaddr() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awburst awburst() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awcache awcache() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awid awid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awlen awlen() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awlock awlock() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awprot awprot() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awqos awqos() clocked_by (maxiclk) reset_by(maxireset);
      method awready(emaxi_awready)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_awready);
      method emaxi_awsize awsize() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awvalid awvalid() clocked_by (maxiclk) reset_by(maxireset);
      method bid(emaxi_bid) enable((*inhigh*) EN_emaxi_bid);
      method emaxi_bready bready() clocked_by (maxiclk) reset_by(maxireset);
      method bresp(emaxi_bresp)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_bresp);
      method bvalid(emaxi_bvalid)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_bvalid);
      method rdata(emaxi_rdata)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rdata);
      method rid(emaxi_rid)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rid);
      method rlast(emaxi_rlast)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rlast);
      method emaxi_rready rready() clocked_by (maxiclk) reset_by(maxireset);
      method rresp(emaxi_rresp)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rresp);
      method rvalid(emaxi_rvalid)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rvalid);
      method emaxi_wdata wdata() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_wid wid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_wlast wlast() clocked_by (maxiclk) reset_by(maxireset);
      method wready(emaxi_wready)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_wready);
      method emaxi_wstrb wstrb() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_wvalid wvalid() clocked_by (maxiclk) reset_by(maxireset);
   endinterface

   interface Par_saxi;
      method araddr(esaxi_araddr) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_araddr);
      method arburst(esaxi_arburst) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arburst);
      method arcache(esaxi_arcache) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arcache);
      method esaxi_aresetn aresetn() clocked_by(saxiclk) reset_by(saxireset);
      method arid(esaxi_arid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arid);
      method arlen(esaxi_arlen) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arlen);
      method arlock(esaxi_arlock) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arlock);
      method arprot(esaxi_arprot) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arprot);
      method arqos(esaxi_arqos) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arqos);
      method esaxi_arready arready() clocked_by(saxiclk) reset_by(saxireset);
      method arsize(esaxi_arsize) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arsize);
      method arvalid(esaxi_arvalid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arvalid);
      method awaddr(esaxi_awaddr) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awaddr);
      method awburst(esaxi_awburst) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awburst);
      method awcache(esaxi_awcache) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awcache);
      method awid(esaxi_awid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awid);
      method awlen(esaxi_awlen) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awlen);
      method awlock(esaxi_awlock) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awlock);
      method awprot(esaxi_awprot) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awprot);
      method awqos(esaxi_awqos) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awqos);
      method esaxi_awready awready() clocked_by(saxiclk) reset_by(saxireset);
      method awsize(esaxi_awsize) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awsize);
      method awvalid(esaxi_awvalid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awvalid);
      method esaxi_bid bid() clocked_by(saxiclk) reset_by(saxireset);
      method bready(esaxi_bready) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_bready);
      method esaxi_bresp bresp() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_bvalid bvalid() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_rdata rdata() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_rlast rlast() clocked_by(saxiclk) reset_by(saxireset);
      method rready(esaxi_rready) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_rready);
      method esaxi_rresp rresp() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_rvalid rvalid() clocked_by(saxiclk) reset_by(saxireset);
      method wdata(esaxi_wdata) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wdata);
      method wid(esaxi_wid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wid);
      method wlast(esaxi_wlast) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wlast);
      method esaxi_wready wready() clocked_by(saxiclk) reset_by(saxireset);
      method wstrb(esaxi_wstrb) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wstrb);
      method wvalid(esaxi_wvalid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wvalid);
      method esaxi_rid rid() clocked_by(saxiclk) reset_by(saxireset);
      interface extraType   extra;
   endinterface

schedule (
   misc.csysack, misc.cactive, misc.reset_chip, misc.reset_fpga, txo.data_p, txo.data_n,
   txo.frame_p, txo.frame_n, txo.lclk_p, txo.lclk_n, rxo.wr_wait_p,
   rxo.wr_wait_n, rxo.rd_wait_p, rxo.rd_wait_n, rxi.cclk_p,
   rxi.cclk_n, maxi.awid, maxi.awaddr, maxi.awlen, maxi.awsize,
   maxi.awburst, maxi.awlock, maxi.awcache, maxi.awprot,
   maxi.awvalid, saxi.awready, maxi.wid, maxi.wdata, maxi.wstrb,
   maxi.wlast, maxi.wvalid, saxi.wready, maxi.bready, saxi.bid,
   saxi.bresp, saxi.bvalid, maxi.arid, maxi.araddr, maxi.arlen,
   maxi.arsize, maxi.arburst, maxi.arlock, maxi.arcache,
   maxi.arprot, maxi.arvalid, saxi.arready, maxi.rready,
   saxi.rid, saxi.rdata, saxi.rresp, saxi.rlast, saxi.rvalid,
   maxi.awqos, maxi.arqos,
   // Inputs
   // clkin_100, saxi.aclk, maxi.aclk, reset,
   saxi.aresetn,
   maxi.aresetn, csysreq, rxi.data_p, rxi.data_n, rxi.frame_p,
   rxi.frame_n, rxi.lclk_p, rxi.lclk_n, txi.wr_wait_p, txi.wr_wait_n,
   txi.rd_wait_p, txi.rd_wait_n, maxi.awready, saxi.awid,
   saxi.awaddr, saxi.awlen, saxi.awsize, saxi.awburst,
   saxi.awlock, saxi.awcache, saxi.awprot, saxi.awvalid,
   maxi.wready, saxi.wid, saxi.wdata, saxi.wstrb, saxi.wlast,
   saxi.wvalid, maxi.bid, maxi.bresp, maxi.bvalid, saxi.bready,
   maxi.arready, saxi.arid, saxi.araddr, saxi.arlen, saxi.arsize,
   saxi.arburst, saxi.arlock, saxi.arcache, saxi.arprot,
   saxi.arvalid, maxi.rid, maxi.rdata, maxi.rresp, maxi.rlast,
   maxi.rvalid, saxi.rready, saxi.awqos, saxi.arqos
) CF (
   misc.csysack, misc.cactive, misc.reset_chip, misc.reset_fpga, txo.data_p, txo.data_n,
   txo.frame_p, txo.frame_n, txo.lclk_p, txo.lclk_n, rxo.wr_wait_p,
   rxo.wr_wait_n, rxo.rd_wait_p, rxo.rd_wait_n, rxi.cclk_p,
   rxi.cclk_n, maxi.awid, maxi.awaddr, maxi.awlen, maxi.awsize,
   maxi.awburst, maxi.awlock, maxi.awcache, maxi.awprot,
   maxi.awvalid, saxi.awready, maxi.wid, maxi.wdata, maxi.wstrb,
   maxi.wlast, maxi.wvalid, saxi.wready, maxi.bready, saxi.bid,
   saxi.bresp, saxi.bvalid, maxi.arid, maxi.araddr, maxi.arlen,
   maxi.arsize, maxi.arburst, maxi.arlock, maxi.arcache,
   maxi.arprot, maxi.arvalid, saxi.arready, maxi.rready,
   saxi.rid, saxi.rdata, saxi.rresp, saxi.rlast, saxi.rvalid,
   maxi.awqos, maxi.arqos,
   // Inputs
   // clkin_100, saxi.aclk, maxi.aclk, reset,
   saxi.aresetn,
   maxi.aresetn, csysreq, rxi.data_p, rxi.data_n, rxi.frame_p,
   rxi.frame_n, rxi.lclk_p, rxi.lclk_n, txi.wr_wait_p, txi.wr_wait_n,
   txi.rd_wait_p, txi.rd_wait_n, maxi.awready, saxi.awid,
   saxi.awaddr, saxi.awlen, saxi.awsize, saxi.awburst,
   saxi.awlock, saxi.awcache, saxi.awprot, saxi.awvalid,
   maxi.wready, saxi.wid, saxi.wdata, saxi.wstrb, saxi.wlast,
   saxi.wvalid, maxi.bid, maxi.bresp, maxi.bvalid, saxi.bready,
   maxi.arready, saxi.arid, saxi.araddr, saxi.arlen, saxi.arsize,
   saxi.arburst, saxi.arlock, saxi.arcache, saxi.arprot,
   saxi.arvalid, maxi.rid, maxi.rdata, maxi.rresp, maxi.rlast,
   maxi.rvalid, saxi.rready, saxi.awqos, saxi.arqos

   );

endmodule

// Copyright (c) 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.

// This file is a hand-generated file that we hope will someday be
// generated automatically by connectal/generated/scripts/importbvi.py
//
// Created by copying the style of connectal/generated/xilinx/PPS7LIB.bsv

import Clocks::*;
import DefaultValue::*;
import XilinxCells::*;
import GetPut::*;
import AxiBits::*;

// The name of this interface is a prefix "Par_" plus the common prefix of the signals "txo"
// Hopefully this is what importbvi.py would do
interface Par_txo;
   method Action data_p(Bit#(8) v);
   method Action data_n(Bit#(8) v);
   method Action frame_p(Bit#(1) v);
   method Action frame_n(Bit#(1) v);
   method Action lclk_p(Bit#(1) v);
   method Action lclk_n(Bit#(1) v);
endinterface

interface Par_txi;
   method Bit#(1) wr_wait_p();
   method Bit#(1) wr_wait_n();
   method Bit#(1) rd_wait_p();
   method Bit#(1) rd_wait_n();
endinterface

interface Par_rxi;
   method Bit#(8) data_p();
   method Bit#(8) data_n();
   method Bit#(1) frame_p();
   method Bit#(1) frame_n();
   method Bit#(1) lclk_p();
   method Bit#(1) lclk_n();
   method Action cclk_p(Bit#(1));
   method Action cclk_n(Bit#(1));
endinterface

interface Par_rxo;
   method Action wr_wait_p(Bit#(1) v);
   method Action wr_wait_n(Bit#(1) v);
   method Action rd_wait_p(Bit#(1) v);
   method Action rd_wait_n(Bit#(1) v);
endinterface

interface Par_misc;
   method Bit#(1) cactive();
   method Bit#(1) csysack();
   method Action reset_chip();
   method Action reset_fpga();
endinterface
//

interface PParallellaLib;
   interface Par_txo txo;
   interface Par_txi txi;
   interface Par_rxo rxo;
   interface Par_rxi rxi;
   interface AxiMaster#(32,32,6) maxi;
   interface AxiSlave#(64, 32, 6) saxi;
   interface Par_misc misc;
endinterface;

module mkPParallellaLIB#(Clock maxiclk, Clock saxiclk,
   Reset maxiclk_reset, Reset saxiclk_reset,\
   Reset maxireset, Reset saxireset,
   Reset reset_chip, Reset reset_fpga)(PParallellaLib);
   default_clock clk();
   default_reset rst();
   input_clock maxiclk(emaxi_aclk) = maxiclk;  // assigns the verilog emaxi_aclk
   input_clock saxiclk(esaxi_aclk) = saxiclk;  // assigns the verilog esaxi_aclk
   input_reset maxiclk_reset() = maxiclk_reset; /* from clock*/
   input_reset saxiclk_reset() = saxiclk_reset; /* from clock*/

   interface Par_misc;
   method cactive(cactive);
   method csysack(csysack);
   method reset_chip(reset_chip) enable((*inhigh*) EN_reset_chip);
   method reset_fpga(reset_fpga) enable((*inhigh*) EN_reset_fpga);
   endinterface

   interface Par_txo;
      method data_p(txo_data_p) enable((*inhigh*) EN_txo_data_p);
      method data_n(txo_data_n) enable((*inhigh*) EN_txo_data_n);
      method frame_p(txo_frame_p) enable((*inhigh*) EN_txo_frame_p);
      method frame_n(txo_frame_n) enable((*inhigh*) EN_txo_frame_n);
   endinterface

   interface Par_txi;
      method txo_wr_wait_p wr_wait_p();
      method txo_wr_wait_n wr_wait_n();
      method txo_rd_wait_p rd_wait_p();
      method txo_rd_wait_n rd_wait_n();
   endinterface

   interface Par_rxi;
      method rxi_data_p data_p();
      method rxi_data_n data_n();
      method rxi_frame_p frame_p();
      method rxi_frame_n frame_n();
   endinterface

   interface Par_rxo;
      method wr_wait_p(rxo_wr_wait_p) enable((*inhigh*) EN_rxo_wr_wait_p);
      method wr_wait_n(rxo_wr_wait_n) enable((*inhigh*) EN_rxo_wr_wait_n);
      method rd_wait_p(rxo_rd_wait_p) enable((*inhigh*) EN_rxo_rd_wait_p);
      method rd_wait_n(rxo_rd_wait_n) enable((*inhigh*) EN_rxo_rd_wait_n);
      method cclk_p(rxi_cclk_p) enable((*inhigh*) EN_rxi_cclk_p);
      method cclk_n(rxi_cclk_n) enable((*inhigh*) EN_rxi_cclk_p);
   endinterface

   interface Par_emaxi;
      method emaxi_araddr araddr() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arburst arburst() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arcache arcache() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_aresetn aresetn() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arid arid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arlen arlen() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arlock arlock() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arprot arprot() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arqos arqos() clocked_by (maxiclk) reset_by(maxireset);
      method arready(emaxi_arready)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_arready);
      method emaxi_arsize arsize() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_arvalid arvalid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awaddr awaddr() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awburst awburst() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awcache awcache() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awid awid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awlen awlen() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awlock awlock() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awprot awprot() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awqos awqos() clocked_by (maxiclk) reset_by(maxireset);
      method awready(emaxi_awready)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_awready);
      method emaxi_awsize awsize() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_awvalid awvalid() clocked_by (maxiclk) reset_by(maxireset);
      method bid(emaxi_bid) enable((*inhigh*) EN_emaxi_bid);
      method emaxi_bready bready() clocked_by (maxiclk) reset_by(maxireset);
      method bresp(emaxi_bresp)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_bresp);
      method bvalid(emaxi_bvalid)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_bvalid);
      method rdata(emaxi_rdata)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rdata);
      method rid(emaxi_rid)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rid);
      method rlast(emaxi_rlast)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rlast);
      method emaxi_rready rready() clocked_by (maxiclk) reset_by(maxireset);
      method rresp(emaxi_rresp)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rresp);
      method rvalid(emaxi_rvalid)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_rvalid);
      method emaxi_wdata wdata() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_wid wid() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_wlast wlast() clocked_by (maxiclk) reset_by(maxireset);
      method wready(emaxi_wready)  clocked_by (maxiclk) reset_by(maxireset) enable((*inhigh*) EN_emaxi_wready);
      method emaxi_wstrb wstrb() clocked_by (maxiclk) reset_by(maxireset);
      method emaxi_wvalid wvalid() clocked_by (maxiclk) reset_by(maxireset);
   endinterface

   interface Par_saxi;
      method araddr(esaxi_araddr) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_araddr);
      method arburst(esaxi_arburst) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arburst);
      method arcache(esaxi_arcache) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arcache);
      method esaxi_aresetn aresetn() clocked_by(saxiclk) reset_by(saxireset);
      method arid(esaxi_arid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arid);
      method arlen(esaxi_arlen) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arlen);
      method arlock(esaxi_arlock) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arlock);
      method arprot(esaxi_arprot) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arprot);
      method arqos(esaxi_arqos) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arqos);
      method esaxi_arready arready() clocked_by(saxiclk) reset_by(saxireset);
      method arsize(esaxi_arsize) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arsize);
      method arvalid(esaxi_arvalid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_arvalid);
      method awaddr(esaxi_awaddr) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awaddr);
      method awburst(esaxi_awburst) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awburst);
      method awcache(esaxi_awcache) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awcache);
      method awid(esaxi_awid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awid);
      method awlen(esaxi_awlen) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awlen);
      method awlock(esaxi_awlock) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awlock);
      method awprot(esaxi_awprot) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awprot);
      method awqos(esaxi_awqos) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awqos);
      method esaxi_awready awready() clocked_by(saxiclk) reset_by(saxireset);
      method awsize(esaxi_awsize) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awsize);
      method awvalid(esaxi_awvalid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_awvalid);
      method esaxi_bid bid() clocked_by(saxiclk) reset_by(saxireset);
      method bready(esaxi_bready) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_bready);
      method esaxi_bresp bresp() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_bvalid bvalid() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_rdata rdata() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_rlast rlast() clocked_by(saxiclk) reset_by(saxireset);
      method rready(esaxi_rready) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_rready);
      method esaxi_rresp rresp() clocked_by(saxiclk) reset_by(saxireset);
      method esaxi_rvalid rvalid() clocked_by(saxiclk) reset_by(saxireset);
      method wdata(esaxi_wdata) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wdata);
      method wid(esaxi_wid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wid);
      method wlast(esaxi_wlast) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wlast);
      method esaxi_wready wready() clocked_by(saxiclk) reset_by(saxireset);
      method wstrb(esaxi_wstrb) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wstrb);
      method wvalid(esaxi_wvalid) clocked_by(saxiclk) reset_by(saxireset) enable((*inhigh*) EN_esaxi_wvalid);
      method esaxi_rid rid() clocked_by(saxiclk) reset_by(saxireset);
      interface extraType   extra;
   endinterface

schedule (
   misc.csysack, misc.cactive, misc.reset_chip, misc.reset_fpga, txo.data_p, txo.data_n,
   txo.frame_p, txo.frame_n, txo.lclk_p, txo.lclk_n, rxo.wr_wait_p,
   rxo.wr_wait_n, rxo.rd_wait_p, rxo.rd_wait_n, rxi.cclk_p,
   rxi.cclk_n, maxi.awid, maxi.awaddr, maxi.awlen, maxi.awsize,
   maxi.awburst, maxi.awlock, maxi.awcache, maxi.awprot,
   maxi.awvalid, saxi.awready, maxi.wid, maxi.wdata, maxi.wstrb,
   maxi.wlast, maxi.wvalid, saxi.wready, maxi.bready, saxi.bid,
   saxi.bresp, saxi.bvalid, maxi.arid, maxi.araddr, maxi.arlen,
   maxi.arsize, maxi.arburst, maxi.arlock, maxi.arcache,
   maxi.arprot, maxi.arvalid, saxi.arready, maxi.rready,
   saxi.rid, saxi.rdata, saxi.rresp, saxi.rlast, saxi.rvalid,
   maxi.awqos, maxi.arqos,
   // Inputs
   // clkin_100, saxi.aclk, maxi.aclk, reset,
   saxi.aresetn,
   maxi.aresetn, csysreq, rxi.data_p, rxi.data_n, rxi.frame_p,
   rxi.frame_n, rxi.lclk_p, rxi.lclk_n, txi.wr_wait_p, txi.wr_wait_n,
   txi.rd_wait_p, txi.rd_wait_n, maxi.awready, saxi.awid,
   saxi.awaddr, saxi.awlen, saxi.awsize, saxi.awburst,
   saxi.awlock, saxi.awcache, saxi.awprot, saxi.awvalid,
   maxi.wready, saxi.wid, saxi.wdata, saxi.wstrb, saxi.wlast,
   saxi.wvalid, maxi.bid, maxi.bresp, maxi.bvalid, saxi.bready,
   maxi.arready, saxi.arid, saxi.araddr, saxi.arlen, saxi.arsize,
   saxi.arburst, saxi.arlock, saxi.arcache, saxi.arprot,
   saxi.arvalid, maxi.rid, maxi.rdata, maxi.rresp, maxi.rlast,
   maxi.rvalid, saxi.rready, saxi.awqos, saxi.arqos
) CF (
   misc.csysack, misc.cactive, misc.reset_chip, misc.reset_fpga, txo.data_p, txo.data_n,
   txo.frame_p, txo.frame_n, txo.lclk_p, txo.lclk_n, rxo.wr_wait_p,
   rxo.wr_wait_n, rxo.rd_wait_p, rxo.rd_wait_n, rxi.cclk_p,
   rxi.cclk_n, maxi.awid, maxi.awaddr, maxi.awlen, maxi.awsize,
   maxi.awburst, maxi.awlock, maxi.awcache, maxi.awprot,
   maxi.awvalid, saxi.awready, maxi.wid, maxi.wdata, maxi.wstrb,
   maxi.wlast, maxi.wvalid, saxi.wready, maxi.bready, saxi.bid,
   saxi.bresp, saxi.bvalid, maxi.arid, maxi.araddr, maxi.arlen,
   maxi.arsize, maxi.arburst, maxi.arlock, maxi.arcache,
   maxi.arprot, maxi.arvalid, saxi.arready, maxi.rready,
   saxi.rid, saxi.rdata, saxi.rresp, saxi.rlast, saxi.rvalid,
   maxi.awqos, maxi.arqos,
   // Inputs
   // clkin_100, saxi.aclk, maxi.aclk, reset,
   saxi.aresetn,
   maxi.aresetn, csysreq, rxi.data_p, rxi.data_n, rxi.frame_p,
   rxi.frame_n, rxi.lclk_p, rxi.lclk_n, txi.wr_wait_p, txi.wr_wait_n,
   txi.rd_wait_p, txi.rd_wait_n, maxi.awready, saxi.awid,
   saxi.awaddr, saxi.awlen, saxi.awsize, saxi.awburst,
   saxi.awlock, saxi.awcache, saxi.awprot, saxi.awvalid,
   maxi.wready, saxi.wid, saxi.wdata, saxi.wstrb, saxi.wlast,
   saxi.wvalid, maxi.bid, maxi.bresp, maxi.bvalid, saxi.bready,
   maxi.arready, saxi.arid, saxi.araddr, saxi.arlen, saxi.arsize,
   saxi.arburst, saxi.arlock, saxi.arcache, saxi.arprot,
   saxi.arvalid, maxi.rid, maxi.rdata, maxi.rresp, maxi.rlast,
   maxi.rvalid, saxi.rready, saxi.awqos, saxi.arqos

   );

endmodule