Use RangePipe to calculate matrix offsets

// 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 MIMO::*;
import DefaultValue::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import DmaVector::*;
import PortalMemory::*;
import Dma::*;
import FloatingPoint::*;
import Pipe::*;
import FloatOps::*;
import Timer::*;
import RbmTypes::*;
import Assert::*;

interface DotProdServer#(numeric type n);
   interface Reg#(UInt#(20)) numElts;
   interface Put#(Tuple2#(Vector#(n,Float),Vector#(n,Float))) request;
   interface PipeOut#(Float) pipe;
endinterface

(* synthesize *)
module [Module] mkDotProdServer#(UInt#(TLog#(K)) label)(DotProdServer#(N));

   let n = valueOf(N);
   let add_depth = valueOf(FP_ADD_DEPTH);
   let mul_depth = valueOf(FP_MUL_DEPTH);
   Bool verbose = False; //label==0;

   Reg#(Bit#(TAdd#(TLog#(FP_ADD_DEPTH),1))) initCnt <- mkReg(0);
   FIFO#(void) initCtrl <- mkSizedFIFO(1);

   Reg#(UInt#(20)) numEltsReg <- mkReg(0);
   Reg#(UInt#(20)) countInReg <- mkReg(0);

   Vector#(N, FloatAlu#(FP_MUL_DEPTH)) muls <- replicateM(mkFloatMultiplier(defaultValue));
   Vector#(N, FloatAlu#(FP_ADD_DEPTH)) adders <- replicateM(mkFloatAdder(defaultValue));

   Vector#(N,FIFOF#(Tuple2#(Float,Float))) abfifos <- replicateM(mkFIFOF());
   Vector#(N,FIFOF#(Bool)) lastFifos <- replicateM(mkSizedFIFOF(mul_depth));

   Vector#(N, Reg#(Bit#(TAdd#(TLog#(FP_ADD_DEPTH),1)))) drainCnts <- replicateM(mkReg(0));
   Vector#(N, Reg#(Bool)) drained <- replicateM(mkReg(False));

   Reg#(Maybe#(Float)) accum <- mkReg(Nothing);
   FIFOF#(Float) dotfifo <- mkFIFOF;

   function Bit#(TLog#(N)) i_v(Integer i) = fromInteger(i);

   rule init if (initCnt > 0);
      for(Integer i = 0; i < n; i = i + 1)
	 adders[i].request.put(tuple2(0,0));
      initCnt <= initCnt - 1;
      if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" initCnt=")+fshow(initCnt)));
   endrule

   for (Integer i = 0; i < n; i = i + 1)
      rule mul;
	 // this rule could be folded into the 'put' method to reduce latency
	 match {.x,.y} <- toGet(abfifos[i]).get;
	 muls[i].request.put(tuple2(x, y));
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" mul=")+fshow(i_v(i))));
      endrule

   for (Integer i = 0; i < n; i = i + 1)
      rule acc if (drainCnts[i] == 0 && initCnt == 0);
	 match {.resp,.*} <- muls[i].response.get();
	 match {.acc,.*} <- adders[i].response.get;
	 adders[i].request.put(tuple2(resp,acc));
	 let last <- toGet(lastFifos[i]).get;
	 if (last) begin
	    if (i>0)
	       drainCnts[i] <= fromInteger(add_depth);
	    else
	       drainCnts[i] <= fromInteger((add_depth*2)-1); // is this correct??
	 end
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" acc=")+fshow(i_v(i))+fshow(" last=")+fshow(last)));
      endrule

   for (Integer i = 1; i < n; i = i + 1)
      rule gather if (drainCnts[i] > 0);
	 let new_cnt = drainCnts[i]-1;
	 drained[i] <= (new_cnt==0);
	 drainCnts[i] <= new_cnt;
	 match {.a,.*} <- adders[0].response.get;
	 match {.b,.*} <- adders[i].response.get;
	 adders[0].request.put(tuple2(a,b));
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" gather=")+fshow(i_v(i))+fshow(" drainCnt=")+fshow(drainCnts[i])));
      endrule

   // the reference-guide says this should work, but it doesn't compile:
   // let gathered = and(tail(drained));
   function Bool is_true(Bool b) = b;
   let gathered = all(is_true, readVReg(tail(drained)));
   // this will only work correctly when add_depth is odd
   rule drain if (gathered && drainCnts[0] > 0);
      let new_cnt = drainCnts[0]-1;
      match {.a,.*} <- adders[0].response.get;
      drainCnts[0] <= new_cnt;
      let enq = False;
      if(accum matches tagged Valid .v) begin
	 adders[0].request.put(tuple2(a,v));
	 dynamicAssert(new_cnt > 0, "mkDotProdServer::drain");
	 enq = True;
	 accum <= tagged Invalid;
      end
      else begin
	 if (new_cnt == 0) begin
	    dotfifo.enq(a);
	    initCtrl.deq;
	 end
	 else
	    accum <= tagged Valid a;
      end
      if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" drain0=")+fshow(enq)+fshow(" drainCnt=")+fshow(drainCnts[0])));
   endrule

   PipeOut#(Float) dotpipe = toPipeOut(dotfifo);
   interface Put request;
      method Action put(Tuple2#(Vector#(N,Float),Vector#(N,Float)) tpl);
	 if (countInReg == 0) begin
	    initCtrl.enq(?);
	    initCnt <= fromInteger(add_depth);
	 end
	 let c = countInReg+fromInteger(n);
	 Bool isLast = (c >= numEltsReg);
	 if (isLast) begin
	    c = 0;
	 end
	 countInReg <= c;
	 match { .avec, .bvec } = tpl;
	 function Action enqvalues(Integer i);
	    action
	       abfifos[i].enq(tuple2(avec[i], bvec[i]));
	       lastFifos[i].enq(isLast);
	       //if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" countInReg=(")+fshow(countInReg)+fshow("/")+fshow(numEltsReg)+fshow(") dotprod x=") + fshow(avec[i]) + fshow(" y=") + fshow(bvec[i])));
	    endaction
	 endfunction
	 Vector#(N, Integer) indices = genVector();
	 mapM_(enqvalues, indices);
      endmethod
   endinterface : request
   interface PipeOut pipe = dotpipe;
   interface Reg numElts = numEltsReg;
endmodule : mkDotProdServer

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);
      //$display("XYRangePipe x=%d xlimit=%d xstep=%d y=%d ylimit=%d ystep=%d", cfg.xbase, cfg.xlimit, cfg.xstep, cfg.ybase, cfg.ylimit, cfg.ystep);
      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 xstep=%d ystep=%d", x, xlimit, xstep, y, ylimit, ystep);
   endmethod
endmodule: mkXYRangePipeOut

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

// row major layout
interface DmaMatrixMultiplyIfc#(numeric type addrwidth, numeric type dsz);
   interface ObjectWriteClient#(dsz) dmaClient;
   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
endinterface

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

/*!
 * Multiplies two matrices A and B and writes the result to memory.
 * Fetches J rows at a time from A and K rows at a time from B.
 * Each cycle, it can fetch N elements of a row or column.
 *
 * Just considering memory bandwidth, every J+K cycles it is ready to perform J*K*N multiply accumulates.
 *
 * Currently, requires J == 1.
 */
module [Module] mkDmaMatrixMultiply#(Vector#(J, VectorSource#(dsz, Vector#(N, Float))) sourceA,
				     Vector#(K, VectorSource#(dsz, Vector#(N, Float))) sourceB,
				     function Module#(DmaVectorSink#(dsz, Vector#(N, Float))) mkSink(PipeOut#(Vector#(N, Float)) pipe_in)
				     )(DmaMatrixMultiplyIfc#(addrwidth, dsz))
   provisos (  Add#(N,n__,K)
	     , Mul#(N,m__,K)
	     , Add#(1,0,J)
	     , Log#(N,nshift)
	     , FShow#(Float)
	     , Arith#(Float)
	     , Bits#(Vector#(N, Float), dsz)
	     , Bits#(MatrixDescriptor#(UInt#(addrwidth)), mdsz)
	     , Bits#(Tuple2#(UInt#(addrwidth), UInt#(addrwidth)), tplsz)
	     , Add#(b__, 20, addrwidth)
	     , Add#(a__, addrwidth, 40)
      );

   let n = valueOf(N);
   let k = valueOf(K);
   let nshift = valueOf(nshift);
   Bool verbose = False;
   Bool verbose1 = False;
   Bool timing = 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)) dotprodCount <- mkReg(0);

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

   function Module#(DotProdServer#(N)) mkFxDotProd(Integer i);
      return mkDotProdServer(fromInteger(i));
   endfunction
   Vector#(K, DotProdServer#(N)) fxdotprods <- genWithM(mkFxDotProd);
   for (Integer i = 0; i < k; i = i+1)
      rule connectDotProd;
	 let a = aPipes[i].first();
	 aPipes[i].deq();
	 let b = sourceB[i].pipe.first();
	 sourceB[i].pipe.deq();
	 fxdotprods[i].request.put(tuple2(a, b));
      endrule

   MIMOConfiguration mimoCfg = defaultValue;
   MIMO#(K,N,K,Float) dfifo <- mkMIMO(mimoCfg);
   let sinkC <- mkSink(toPipeOut(dfifo));

   XYRangePipeIfc#(UInt#(addrwidth)) indexpipeifc <- mkXYRangePipeOut();
   XYRangePipeIfc#(UInt#(addrwidth)) offsetpipeA <- mkXYRangePipeOut();
   XYRangePipeIfc#(UInt#(addrwidth)) offsetpipeB <- mkXYRangePipeOut();
   XYRangePipeIfc#(UInt#(addrwidth)) offsetpipeC <- mkXYRangePipeOut();

   Vector#(TAdd#(K,2), PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth)))) indexpipes <- mkForkVector(indexpipeifc.pipe);
   Vector#(K, PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth))))        offsetpipesA <- mkForkVector(offsetpipeA.pipe);
   Vector#(K, PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth))))        offsetpipesB <- mkForkVector(offsetpipeB.pipe);
   Vector#(K, PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth))))        offsetpipesC <- mkForkVector(offsetpipeC.pipe);

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

   Reg#(UInt#(32)) cycles <- mkReg(0);
   rule countCycles;
      cycles <= cycles+1;
   endrule

   Vector#(K, Reg#(UInt#(addrwidth))) startBOffset <- replicateM(mkReg(0));
   for (Integer i = 0; i < k; i = i + 1) begin
      FIFO#(UInt#(addrwidth)) startAFifo <- mkFIFO();
      //FIFO#(UInt#(addrwidth)) startBFifo <- mkFIFO();
      FIFO#(UInt#(addrwidth)) startCFifo <- mkFIFO();
      FIFO#(UInt#(addrwidth))    colFifo <- mkFIFO();
      rule startDotProd1;
	 Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) index <- toGet(indexpipes[i]).get();
	 match { .startAcheck, .unusedA } <- toGet(offsetpipesA[i]).get();
	 match { .unusedB, .startBcheck } <- toGet(offsetpipesB[i]).get();
	 match { .startCcheck, .unusedC } <- toGet(offsetpipesC[i]).get();

	 UInt#(TLog#(K)) in = fromInteger(i);
	 int i_v = fromInteger(i);

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

	 let startA = row*descriptorA.numColumns; // row major
	 let startB = col*descriptorB.numColumns; // col major layout (pre-transposed)
	 let startC = row*descriptorC.numColumns; // + col; // row major
	 if (startA != startAcheck)
	    $display("startAmismatch row=%d col=%d startA=%d startAcheck=%d", row, col, startA, startAcheck);
	 if (startB != (startBcheck + startBOffset[i]))
	    $display("startBmismatch row=%d col=%d startB=%d startBcheck=%d i=%d", row, col, startB, startBcheck, i_v);
	 if (startC != startCcheck)
	    $display("startCmismatch row=%d col=%d startC=%d startCcheck=%d", row, col, startC, startCcheck);

	 if (timing || verbose) $display($format(fshow(cycles)+fshow("    startDotProd index=")+fshow(tuple2(row,col))
	    +fshow(" startA=")+fshow(startA)
	    +fshow(" startB=")+fshow(startB)
	    +fshow(" startC=")+fshow(startC+col)
	    +fshow(" k=")+fshow(i_v)));

	 if (i == 0) begin
	    startCFifo.enq(startC);
	 end
	 if (i == 0) begin
	    startAFifo.enq(startA);
	 end
	 colFifo.enq(col);
	 //startBFifo.enq(startB);
	 if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].start")+fshow(startB)));
      endrule
      rule startDotProd2;
	 UInt#(TLog#(K)) in = fromInteger(i);
	 let col <- toGet(colFifo).get();
	 if (i == 0) begin
	    let startC <- toGet(startCFifo).get();
	    startC = startC + col;
	    sinkC.vector.start(descriptorC.pointer, pack(extend(startC>>nshift)), fromInteger(k/n));
	    if (verbose || verbose1) $display($format(fshow(cycles)+fshow("      sinkC[")+fshow(in)+fshow("].start")+fshow(startC)));
	 end
	 if (i == 0) begin
	    let startA <- toGet(startAFifo).get();
	    sourceA[0].start(descriptorA.pointer, pack(extend(startA>>nshift)), pack(extend(descriptorA.numColumns>>nshift)));
	    if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceA[0].start")+fshow(startA)));
	 end
	 let startB = col*descriptorB.numColumns; // col major layout (pre-transposed)
	 sourceB[i].start(descriptorB.pointer, pack(extend(startB>>nshift)), pack(extend(descriptorB.numColumns>>nshift)));
      endrule
      if (i == 0)
	 rule finishSourceA;
	    if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceA[0].finish ")));
	    let b <- sourceA[0].finish();
	 endrule
      rule finishSourceB;
	 UInt#(TLog#(K)) in = fromInteger(i);
	 if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].finish")));
	 let b <- sourceB[i].finish();
      endrule
   end

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

   rule sinkDone;
      // each time we write a burst of k values via sinkC
      let index = indexpipes[k+1].first;
      indexpipes[k+1].deq;
      let b <- sinkC.vector.finish();
      let c = dotprodCount-fromInteger(k);
      if (verbose) $display($format(fshow(cycles)+fshow("    sinkDone c")+fshow(c)+fshow("    index=")+fshow(index)));
      dotprodCount <= c;
      if (c == 0) begin
	 running <= False;
	 doneFifo.enq(?);
      end
   endrule

   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC) if (!running);
      XYRangeConfig#(UInt#(addrwidth)) indexcfg  = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
								  ybase: 0, ylimit: numRowsB, ystep: fromInteger(k) };
      XYRangeConfig#(UInt#(addrwidth)) offsetcfgA = XYRangeConfig {xbase: 0, xlimit: numRowsA*numColumnsA, xstep: numColumnsA,
								  ybase: 0, ylimit: numRowsB, ystep: fromInteger(k) };
      XYRangeConfig#(UInt#(addrwidth)) offsetcfgB = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
								  ybase: 0, ylimit: numRowsB*numColumnsB, ystep: fromInteger(k)*numColumnsB };
      XYRangeConfig#(UInt#(addrwidth)) offsetcfgC = XYRangeConfig {xbase: 0, xlimit: numRowsA*numRowsB, xstep: numRowsB,
								  ybase: 0, ylimit: numRowsB, ystep: fromInteger(k) };
      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};
      dotprodCount <= numRowsA*numRowsB;
      running <= True;

      if (verbose) $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 dotprodCount=%d", numRowsA, numColumnsA, numRowsB, numColumnsB, dotprodCount);
      if (verbose) $display($format(fshow("mm.start ")+fshow(indexcfg)));
      indexpipeifc.start(indexcfg);
      offsetpipeA.start(offsetcfgA);
      offsetpipeB.start(offsetcfgB);
      offsetpipeC.start(offsetcfgC);
      for (Integer i = 0; i < k; i = i + 1) begin
	 fxdotprods[i].numElts <= truncate(numColumnsA);
	 startBOffset[i] <= fromInteger(i)*numColumnsB;
      end
   endmethod
   method ActionValue#(Bool) finish();
      if (verbose) $display("mm.finish()");
      doneFifo.deq();
      return True;
   endmethod

   interface ObjectWriteClient dmaClient = sinkC.dmaClient;
endmodule

typedef 20 MMSize;

interface DramMatrixMultiply#(numeric type n, numeric type dmasz);
   interface Vector#(TAdd#(K,1), ObjectReadClient#(dmasz)) readClients;
   interface Vector#(1, ObjectWriteClient#(dmasz)) writeClients;
   method Action start(ObjectPointer pointerA, UInt#(MMSize) numRowsA, UInt#(MMSize) numColumnsA,
		       ObjectPointer pointerB, UInt#(MMSize) numRowsB, UInt#(MMSize) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
   method Bit#(32) dbg();
endinterface

(* synthesize *)
module [Module] mkDramMatrixMultiply(DramMatrixMultiply#(N,TMul#(N,32)));
   Vector#(TAdd#(K,J), DmaVectorSource#(DmaSz, Vector#(N,Float))) vfsources <- replicateM(mkDmaVectorSource());
   Vector#(J, VectorSource#(DmaSz, Vector#(N,Float))) xvfsources = cons(vfsources[0].vector, nil);
   Vector#(K, VectorSource#(DmaSz, Vector#(N,Float))) yvfsources = takeAt(1, map(dmaVectorSourceVector, vfsources));
   DmaMatrixMultiplyIfc#(MMSize,DmaSz) dmaMMF <- mkDmaMatrixMultiply(xvfsources, yvfsources, mkDmaVectorSink);
   interface Vector readClients = map(getSourceReadClient, vfsources);
   interface Vector writeClients = cons(dmaMMF.dmaClient, nil);
   method start = dmaMMF.start;
   method finish = dmaMMF.finish;
   method Bit#(32) dbg();
      Bit#(32) d = 0;
      d[0] = pack(vfsources[0].vector.pipe.notEmpty());
      d[1] = pack(vfsources[1].vector.pipe.notEmpty());
      return d;
   endmethod
endmodule

interface Mm#(numeric type n);
   interface MmRequest mmRequest;
   interface TimerRequest timerRequest;
   interface Vector#(TAdd#(K,J), ObjectReadClient#(TMul#(32,N))) readClients;
   interface Vector#(1, ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module [Module] mkMm#(MmIndication ind, TimerIndication timerInd)(Mm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz)
      );

   let n = valueOf(n);

   DramMatrixMultiply#(N, TMul#(N,32)) dmaMMF <- mkDramMatrixMultiply();

   Reg#(Bit#(64)) mmfCycles <- mkReg(0);
   rule countMmfCycles;
      mmfCycles <= mmfCycles + 1;
   endrule

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   rule mmfDone;
      let d <- dmaMMF.finish();
      busyFifo.deq();
      ind.mmfDone(mmfCycles);
   endrule

   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   interface TimerRequest timerRequest;
      method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface

   interface MmRequest mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3);
	 dmaMMF.start(h1, unpack(truncate(r1)), unpack(truncate(c1)),
		      h2, unpack(truncate(r2)), unpack(truncate(c2)),
		      h3);
	 mmfCycles <= 0;
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface Vector readClients = dmaMMF.readClients;
   interface Vector writeClients =  dmaMMF.writeClients;

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 MIMO::*;
import DefaultValue::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import DmaVector::*;
import PortalMemory::*;
import Dma::*;
import FloatingPoint::*;
import Pipe::*;
import FloatOps::*;
import Timer::*;
import RbmTypes::*;
import Assert::*;

interface DotProdServer#(numeric type n);
   interface Reg#(UInt#(20)) numElts;
   interface Put#(Tuple2#(Vector#(n,Float),Vector#(n,Float))) request;
   interface PipeOut#(Float) pipe;
endinterface

(* synthesize *)
module [Module] mkDotProdServer#(UInt#(TLog#(K)) label)(DotProdServer#(N));

   let n = valueOf(N);
   let add_depth = valueOf(FP_ADD_DEPTH);
   let mul_depth = valueOf(FP_MUL_DEPTH);
   Bool verbose = False; //label==0;

   Reg#(Bit#(TAdd#(TLog#(FP_ADD_DEPTH),1))) initCnt <- mkReg(0);
   FIFO#(void) initCtrl <- mkSizedFIFO(1);

   Reg#(UInt#(20)) numEltsReg <- mkReg(0);
   Reg#(UInt#(20)) countInReg <- mkReg(0);

   Vector#(N, FloatAlu#(FP_MUL_DEPTH)) muls <- replicateM(mkFloatMultiplier(defaultValue));
   Vector#(N, FloatAlu#(FP_ADD_DEPTH)) adders <- replicateM(mkFloatAdder(defaultValue));

   Vector#(N,FIFOF#(Tuple2#(Float,Float))) abfifos <- replicateM(mkFIFOF());
   Vector#(N,FIFOF#(Bool)) lastFifos <- replicateM(mkSizedFIFOF(mul_depth));

   Vector#(N, Reg#(Bit#(TAdd#(TLog#(FP_ADD_DEPTH),1)))) drainCnts <- replicateM(mkReg(0));
   Vector#(N, Reg#(Bool)) drained <- replicateM(mkReg(False));

   Reg#(Maybe#(Float)) accum <- mkReg(Nothing);
   FIFOF#(Float) dotfifo <- mkFIFOF;

   function Bit#(TLog#(N)) i_v(Integer i) = fromInteger(i);

   rule init if (initCnt > 0);
      for(Integer i = 0; i < n; i = i + 1)
	 adders[i].request.put(tuple2(0,0));
      initCnt <= initCnt - 1;
      if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" initCnt=")+fshow(initCnt)));
   endrule

   for (Integer i = 0; i < n; i = i + 1)
      rule mul;
	 // this rule could be folded into the 'put' method to reduce latency
	 match {.x,.y} <- toGet(abfifos[i]).get;
	 muls[i].request.put(tuple2(x, y));
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" mul=")+fshow(i_v(i))));
      endrule

   for (Integer i = 0; i < n; i = i + 1)
      rule acc if (drainCnts[i] == 0 && initCnt == 0);
	 match {.resp,.*} <- muls[i].response.get();
	 match {.acc,.*} <- adders[i].response.get;
	 adders[i].request.put(tuple2(resp,acc));
	 let last <- toGet(lastFifos[i]).get;
	 if (last) begin
	    if (i>0)
	       drainCnts[i] <= fromInteger(add_depth);
	    else
	       drainCnts[i] <= fromInteger((add_depth*2)-1); // is this correct??
	 end
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" acc=")+fshow(i_v(i))+fshow(" last=")+fshow(last)));
      endrule

   for (Integer i = 1; i < n; i = i + 1)
      rule gather if (drainCnts[i] > 0);
	 let new_cnt = drainCnts[i]-1;
	 drained[i] <= (new_cnt==0);
	 drainCnts[i] <= new_cnt;
	 match {.a,.*} <- adders[0].response.get;
	 match {.b,.*} <- adders[i].response.get;
	 adders[0].request.put(tuple2(a,b));
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" gather=")+fshow(i_v(i))+fshow(" drainCnt=")+fshow(drainCnts[i])));
      endrule

   // the reference-guide says this should work, but it doesn't compile:
   // let gathered = and(tail(drained));
   function Bool is_true(Bool b) = b;
   let gathered = all(is_true, readVReg(tail(drained)));
   // this will only work correctly when add_depth is odd
   rule drain if (gathered && drainCnts[0] > 0);
      let new_cnt = drainCnts[0]-1;
      match {.a,.*} <- adders[0].response.get;
      drainCnts[0] <= new_cnt;
      let enq = False;
      if(accum matches tagged Valid .v) begin
	 adders[0].request.put(tuple2(a,v));
	 dynamicAssert(new_cnt > 0, "mkDotProdServer::drain");
	 enq = True;
	 accum <= tagged Invalid;
      end
      else begin
	 if (new_cnt == 0) begin
	    dotfifo.enq(a);
	    initCtrl.deq;
	 end
	 else
	    accum <= tagged Valid a;
      end
      if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" drain0=")+fshow(enq)+fshow(" drainCnt=")+fshow(drainCnts[0])));
   endrule

   PipeOut#(Float) dotpipe = toPipeOut(dotfifo);
   interface Put request;
      method Action put(Tuple2#(Vector#(N,Float),Vector#(N,Float)) tpl);
	 if (countInReg == 0) begin
	    initCtrl.enq(?);
	    initCnt <= fromInteger(add_depth);
	 end
	 let c = countInReg+fromInteger(n);
	 Bool isLast = (c >= numEltsReg);
	 if (isLast) begin
	    c = 0;
	 end
	 countInReg <= c;
	 match { .avec, .bvec } = tpl;
	 function Action enqvalues(Integer i);
	    action
	       abfifos[i].enq(tuple2(avec[i], bvec[i]));
	       lastFifos[i].enq(isLast);
	       //if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" countInReg=(")+fshow(countInReg)+fshow("/")+fshow(numEltsReg)+fshow(") dotprod x=") + fshow(avec[i]) + fshow(" y=") + fshow(bvec[i])));
	    endaction
	 endfunction
	 Vector#(N, Integer) indices = genVector();
	 mapM_(enqvalues, indices);
      endmethod
   endinterface : request
   interface PipeOut pipe = dotpipe;
   interface Reg numElts = numEltsReg;
endmodule : mkDotProdServer

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);
      //$display("XYRangePipe x=%d xlimit=%d xstep=%d y=%d ylimit=%d ystep=%d", cfg.xbase, cfg.xlimit, cfg.xstep, cfg.ybase, cfg.ylimit, cfg.ystep);
      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 xstep=%d ystep=%d", x, xlimit, xstep, y, ylimit, ystep);
   endmethod
endmodule: mkXYRangePipeOut

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

// row major layout
interface DmaMatrixMultiplyIfc#(numeric type addrwidth, numeric type dsz);
   interface ObjectWriteClient#(dsz) dmaClient;
   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
endinterface

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

/*!
 * Multiplies two matrices A and B and writes the result to memory.
 * Fetches J rows at a time from A and K rows at a time from B.
 * Each cycle, it can fetch N elements of a row or column.
 *
 * Just considering memory bandwidth, every J+K cycles it is ready to perform J*K*N multiply accumulates.
 *
 * Currently, requires J == 1.
 */
module [Module] mkDmaMatrixMultiply#(Vector#(J, VectorSource#(dsz, Vector#(N, Float))) sourceA,
				     Vector#(K, VectorSource#(dsz, Vector#(N, Float))) sourceB,
				     function Module#(DmaVectorSink#(dsz, Vector#(N, Float))) mkSink(PipeOut#(Vector#(N, Float)) pipe_in)
				     )(DmaMatrixMultiplyIfc#(addrwidth, dsz))
   provisos (  Add#(N,n__,K)
	     , Mul#(N,m__,K)
	     , Add#(1,0,J)
	     , Log#(N,nshift)
	     , FShow#(Float)
	     , Arith#(Float)
	     , Bits#(Vector#(N, Float), dsz)
	     , Bits#(MatrixDescriptor#(UInt#(addrwidth)), mdsz)
	     , Bits#(Tuple2#(UInt#(addrwidth), UInt#(addrwidth)), tplsz)
	     , Add#(b__, 20, addrwidth)
	     , Add#(a__, addrwidth, 40)
      );

   let n = valueOf(N);
   let k = valueOf(K);
   let nshift = valueOf(nshift);
   Bool verbose = False;
   Bool verbose1 = False;
   Bool timing = 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)) dotprodCount <- mkReg(0);

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

   function Module#(DotProdServer#(N)) mkFxDotProd(Integer i);
      return mkDotProdServer(fromInteger(i));
   endfunction
   Vector#(K, DotProdServer#(N)) fxdotprods <- genWithM(mkFxDotProd);
   for (Integer i = 0; i < k; i = i+1)
      rule connectDotProd;
	 let a = aPipes[i].first();
	 aPipes[i].deq();
	 let b = sourceB[i].pipe.first();
	 sourceB[i].pipe.deq();
	 fxdotprods[i].request.put(tuple2(a, b));
      endrule

   MIMOConfiguration mimoCfg = defaultValue;
   MIMO#(K,N,K,Float) dfifo <- mkMIMO(mimoCfg);
   let sinkC <- mkSink(toPipeOut(dfifo));

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

   Vector#(TAdd#(K,2), PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth)))) indexpipes <- mkForkVector(indexpipeifc.pipe);

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

   Reg#(UInt#(32)) cycles <- mkReg(0);
   rule countCycles;
      cycles <= cycles+1;
   endrule

   for (Integer i = 0; i < k; i = i + 1) begin
      FIFO#(UInt#(addrwidth)) startAFifo <- mkFIFO();
      //FIFO#(UInt#(addrwidth)) startBFifo <- mkFIFO();
      FIFO#(UInt#(addrwidth)) startCFifo <- mkFIFO();
      FIFO#(UInt#(addrwidth))    colFifo <- mkFIFO();
      rule startDotProd1;
	 Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = indexpipes[i].first;
	 indexpipes[i].deq();

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

	 let startA = row*descriptorA.numColumns; // row major
	 let startB = col*descriptorB.numColumns; // col major layout (pre-transposed)
	 let startC = row*descriptorC.numColumns; // + col; // row major

	 int i_v = fromInteger(i);
	 if (timing || verbose) $display($format(fshow(cycles)+fshow("    startDotProd xy=")+fshow(tuple2(row,col))
	    +fshow(" startA=")+fshow(startA)
	    +fshow(" startB=")+fshow(startB)
	    +fshow(" startC=")+fshow(startC+col)
	    +fshow(" k=")+fshow(i_v)));

	 UInt#(TLog#(K)) in = fromInteger(i);
	 if (i == 0) begin
	    startCFifo.enq(startC);
	 end
	 if (i == 0) begin
	    startAFifo.enq(startA);
	 end
	 colFifo.enq(col);
	 //startBFifo.enq(startB);
	 if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].start")+fshow(startB)));
      endrule
      rule startDotProd2;
	 UInt#(TLog#(K)) in = fromInteger(i);
	 let col <- toGet(colFifo).get();
	 if (i == 0) begin
	    let startC <- toGet(startCFifo).get();
	    startC = startC + col;
	    sinkC.vector.start(descriptorC.pointer, pack(extend(startC>>nshift)), fromInteger(k/n));
	    if (verbose || verbose1) $display($format(fshow(cycles)+fshow("      sinkC[")+fshow(in)+fshow("].start")+fshow(startC)));
	 end
	 if (i == 0) begin
	    let startA <- toGet(startAFifo).get();
	    sourceA[0].start(descriptorA.pointer, pack(extend(startA>>nshift)), pack(extend(descriptorA.numColumns>>nshift)));
	    if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceA[0].start")+fshow(startA)));
	 end
	 let startB = col*descriptorB.numColumns; // col major layout (pre-transposed)
	 sourceB[i].start(descriptorB.pointer, pack(extend(startB>>nshift)), pack(extend(descriptorB.numColumns>>nshift)));
      endrule
      if (i == 0)
	 rule finishSourceA;
	    if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceA[0].finish ")));
	    let b <- sourceA[0].finish();
	 endrule
      rule finishSourceB;
	 UInt#(TLog#(K)) in = fromInteger(i);
	 if (verbose || verbose1) $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].finish")));
	 let b <- sourceB[i].finish();
      endrule
   end

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

   rule sinkDone;
      // each time we write a burst of k values via sinkC
      let xy = indexpipes[k+1].first;
      indexpipes[k+1].deq;
      let b <- sinkC.vector.finish();
      let c = dotprodCount-fromInteger(k);
      if (verbose) $display($format(fshow(cycles)+fshow("    sinkDone c")+fshow(c)+fshow("    xy=")+fshow(xy)));
      dotprodCount <= c;
      if (c == 0) begin
	 running <= False;
	 doneFifo.enq(?);
      end
   endrule

   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC) if (!running);
      XYRangeConfig#(UInt#(addrwidth)) xycfg = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
							      ybase: 0, ylimit: numRowsB, ystep: fromInteger(k) };
      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};
      dotprodCount <= numRowsA*numRowsB;
      running <= True;

      if (verbose) $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 dotprodCount=%d", numRowsA, numColumnsA, numRowsB, numColumnsB, dotprodCount);
      if (verbose) $display($format(fshow("mm.start ")+fshow(xycfg)));
      indexpipeifc.start(xycfg);
      for (Integer i = 0; i < k; i = i + 1) begin
	 fxdotprods[i].numElts <= truncate(numColumnsA);
      end
   endmethod
   method ActionValue#(Bool) finish();
      if (verbose) $display("mm.finish()");
      doneFifo.deq();
      return True;
   endmethod

   interface ObjectWriteClient dmaClient = sinkC.dmaClient;
endmodule

typedef 20 MMSize;

interface DramMatrixMultiply#(numeric type n, numeric type dmasz);
   interface Vector#(TAdd#(K,1), ObjectReadClient#(dmasz)) readClients;
   interface Vector#(1, ObjectWriteClient#(dmasz)) writeClients;
   method Action start(ObjectPointer pointerA, UInt#(MMSize) numRowsA, UInt#(MMSize) numColumnsA,
		       ObjectPointer pointerB, UInt#(MMSize) numRowsB, UInt#(MMSize) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
   method Bit#(32) dbg();
endinterface

(* synthesize *)
module [Module] mkDramMatrixMultiply(DramMatrixMultiply#(N,TMul#(N,32)));
   Vector#(TAdd#(K,J), DmaVectorSource#(DmaSz, Vector#(N,Float))) vfsources <- replicateM(mkDmaVectorSource());
   Vector#(J, VectorSource#(DmaSz, Vector#(N,Float))) xvfsources = cons(vfsources[0].vector, nil);
   Vector#(K, VectorSource#(DmaSz, Vector#(N,Float))) yvfsources = takeAt(1, map(dmaVectorSourceVector, vfsources));
   DmaMatrixMultiplyIfc#(MMSize,DmaSz) dmaMMF <- mkDmaMatrixMultiply(xvfsources, yvfsources, mkDmaVectorSink);
   interface Vector readClients = map(getSourceReadClient, vfsources);
   interface Vector writeClients = cons(dmaMMF.dmaClient, nil);
   method start = dmaMMF.start;
   method finish = dmaMMF.finish;
   method Bit#(32) dbg();
      Bit#(32) d = 0;
      d[0] = pack(vfsources[0].vector.pipe.notEmpty());
      d[1] = pack(vfsources[1].vector.pipe.notEmpty());
      return d;
   endmethod
endmodule

interface Mm#(numeric type n);
   interface MmRequest mmRequest;
   interface TimerRequest timerRequest;
   interface Vector#(TAdd#(K,J), ObjectReadClient#(TMul#(32,N))) readClients;
   interface Vector#(1, ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module [Module] mkMm#(MmIndication ind, TimerIndication timerInd)(Mm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz)
      );

   let n = valueOf(n);

   DramMatrixMultiply#(N, TMul#(N,32)) dmaMMF <- mkDramMatrixMultiply();

   Reg#(Bit#(64)) mmfCycles <- mkReg(0);
   rule countMmfCycles;
      mmfCycles <= mmfCycles + 1;
   endrule

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   rule mmfDone;
      let d <- dmaMMF.finish();
      busyFifo.deq();
      ind.mmfDone(mmfCycles);
   endrule

   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   interface TimerRequest timerRequest;
      method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface

   interface MmRequest mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3);
	 dmaMMF.start(h1, unpack(truncate(r1)), unpack(truncate(c1)),
		      h2, unpack(truncate(r2)), unpack(truncate(c2)),
		      h3);
	 mmfCycles <= 0;
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface Vector readClients = dmaMMF.readClients;
   interface Vector writeClients =  dmaMMF.writeClients;

endmodule


AwsF1Top is always ready, always_enabled, plus fix copy/paste error

// Copyright (c) 2017 Connectal Project

// 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 ConnectalConfig::*;
import Vector            :: *;
import GetPut::*;
import Connectable::*;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes:: *;
import MMU:: *;
import MemServer:: *;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import SimDma::*;
import IfcNames::*;
import BuildVector::*;
import AxiBits::*;
import FIFOF::*;
import CFFIFO::*;

`include "ConnectalProjectConfig.bsv"

`ifdef PinTypeInclude
import `PinTypeInclude::*;
`endif
`ifdef PinType
typedef `PinType PinType;
`else
typedef Empty PinType;
`endif

(* always_enabled, always_ready *)
interface AwsF1ClSh;
   method Bit#(1) flr_done();
   method Bit#(32) status0();
   method Bit#(32) status1();
   method Bit#(32) id0();
   method Bit#(32) id1();
   method Bit#(16) status_vled();
endinterface

(* always_enabled, always_ready *)
interface AwsF1ShCl;
   (* prefix="" *)
   method Action flr_assert(Bit#(1) flr_assert);
   (* prefix="" *)
   method Action ctl0(Bit#(32) ctl0);
   (* prefix="" *)
   method Action ctl1(Bit#(32) ctl1);
   (* prefix="" *)
   method Action status_vdip(Bit#(16) status_vdip);
   (* prefix="" *)
   method Action pwr_state(Bit#(2) pwr_state);
endinterface

(* always_ready, always_enabled *)
interface AwsF1Top;
   interface PinType pins;
   interface AwsF1ShCl sh_cl;
   interface AwsF1ClSh cl_sh;
   interface Axi4SlaveBits#(64,512,6,Empty) dmasink;
   interface Axi4SlaveLiteBits#(32,32) ocl;
   interface Axi4SlaveLiteBits#(32,32) sda;
   interface Axi4SlaveLiteBits#(32,32) bar1;
endinterface

module mkAxi4SlaveLiteBitsFromPhysMemSlave#(PhysMemSlave#(addrWidth,dataWidth) slave)
       (Axi4SlaveLiteBits#(axiaddrWidth,dataWidth)) provisos (Div#(dataWidth,8,burstLen),Add#(addrWidth,a__,axiaddrWidth));

    let burstLen = fromInteger(valueOf(burstLen));

    Wire#(Bit#(addrWidth)) araddrWire <- mkDWire(0);
    Wire#(Bit#(1)) arvalidWire <- mkDWire(0);
    Wire#(Bit#(1)) rreadyWire <- mkDWire(0);
    Wire#(Bit#(dataWidth)) rdataWire <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddrWire <- mkDWire(0);
    Wire#(Bit#(1)) awvalidWire <- mkDWire(0);
    Wire#(Bit#(1)) wvalidWire <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdataWire <- mkDWire(0);
    Wire#(Bit#(1)) breadyWire <- mkDWire(0);

    FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arFifo <- mkCFFIFOF();
    FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awFifo <- mkCFFIFOF();
    FIFOF#(MemData#(dataWidth)) rdataFifo <- mkCFFIFOF();
    FIFOF#(MemData#(dataWidth)) wdataFifo <- mkCFFIFOF();
    FIFOF#(Bit#(MemTagSize)) brespFifo <- mkCFFIFOF();

    rule ar_rule if (arvalidWire == 1 && arFifo.notFull());
       let req = PhysMemRequest {addr: araddrWire, burstLen: burstLen, tag: 0 };
       arFifo.enq(req);
    endrule
    rule ar_to_slave;
       let req <- toGet(arFifo).get();
       slave.read_server.readReq.put(req);
    endrule

    rule aw_rule if (awvalidWire == 1 && awFifo.notFull());
       let req = PhysMemRequest {addr: awaddrWire, burstLen: burstLen, tag: 0 };
       awFifo.enq(req);
    endrule
    rule aw_to_slave;
       let req <- toGet(awFifo).get();
       slave.write_server.writeReq.put(req);
    endrule

    rule r_rule if (rreadyWire == 1 && rdataFifo.notEmpty());
       rdataFifo.deq();
    endrule
    rule rdata_rule;
       rdataWire <= rdataFifo.first.data;
    endrule
    rule rdata_from_slave;
       let mdata <- slave.read_server.readData.get();
       rdataFifo.enq(mdata);
    endrule

    rule wdata_rule if (wvalidWire == 1 && wdataFifo.notFull());
       wdataFifo.enq(MemData { data: wdataWire, tag: 0, last: True });
    endrule
    rule wdata_to_slave;
       let mdata <- toGet(wdataFifo).get();
       slave.write_server.writeData.put(mdata);
    endrule

    rule b_rule if (breadyWire == 1 && brespFifo.notEmpty());
       brespFifo.deq();
    endrule
    rule bresp_from_slave;
       let done <- slave.write_server.writeDone.get();
       brespFifo.enq(done);
    endrule

    method Action      araddr(Bit#(axiaddrWidth) v);
       araddrWire <= truncate(v);
    endmethod
    method Bit#(1)     arready();
       return pack(arFifo.notFull());
    endmethod
    method Action      arvalid(Bit#(1) v);
       arvalidWire <= v;
    endmethod
    method Action      awaddr(Bit#(axiaddrWidth) v);
       awaddrWire <= truncate(v);
    endmethod
    method Bit#(1)     awready();
       return pack(awFifo.notFull());
    endmethod
    method Action      awvalid(Bit#(1) v);
       awvalidWire <= v;
    endmethod
    method Action      bready(Bit#(1) v);
       breadyWire <= v;
    endmethod
    method Bit#(2)     bresp();
       return 0; // brespFifo.first();
    endmethod
    method Bit#(1)     bvalid();
       return pack(brespFifo.notEmpty());
    endmethod
    method Bit#(dataWidth)     rdata();
       return rdataWire;
    endmethod
    method Action      rready(Bit#(1) v);
       rreadyWire <= v;
    endmethod
    method Bit#(2)     rresp();
       return 0;
    endmethod
    method Bit#(1)     rvalid();
      return pack(rdataFifo.notEmpty);
    endmethod
    method Action      wdata(Bit#(dataWidth) v);
       wdataWire <= v;
    endmethod
    method Bit#(1)     wready();
       return pack(wdataFifo.notFull());
    endmethod
    method Action      wvalid(Bit#(1) v);
       wvalidWire <= v;
    endmethod
endmodule

(* no_default_clock, no_default_reset, clock_prefix="", reset_prefix="" *)
module mkAwsF1Top#(Clock clk_main_a0, Clock clk_extra_a1, Clock clk_extra_a2, Clock clk_extra_a3,
       Clock  clk_extra_b0, Clock clk_extra_b1, Clock clk_extra_c0, Clock clk_extra_c1,
       Reset kernel_rst_n, Reset rst_main_n
       )(AwsF1Top);

   Clock defaultClock = clk_main_a0;
   Reset defaultReset = rst_main_n;
   Clock derivedClock = clk_main_a0;
   Reset derivedReset = rst_main_n;

   XsimHost host <- mkXsimHost(clk_main_a0, rst_main_n, clk_main_a0);
   let top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`else
`ifdef IMPORT_HOST_CLOCKS // enables synthesis boundary
       derivedClock, derivedReset,
`else
// otherwise no params
`endif
`endif
	clocked_by defaultClock, reset_by defaultReset
       );

   MMUIndicationOutput lMMUIndicationOutput <- mkMMUIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MMURequestInput lMMURequestInput <- mkMMURequestInput(clocked_by defaultClock, reset_by defaultReset);
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMMURequestInput.pipes, lMMU.request, clocked_by defaultClock, reset_by defaultReset);

   MemServerIndicationOutput lMemServerIndicationOutput <- mkMemServerIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MemServerRequestInput lMemServerRequestInput <- mkMemServerRequestInput(clocked_by defaultClock, reset_by defaultReset);
   MemServer::MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(top.readers, top.writers, cons(lMMU,nil), lMemServerIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMemServerRequestInput.pipes, lMemServer.request, clocked_by defaultClock, reset_by defaultReset);

   let lMMUIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MMUIndicationH2S)), lMMUIndicationOutput.portalIfc.indications, lMMUIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMMURequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MMURequestS2H)), lMMURequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MemServerIndicationH2S)), lMemServerIndicationOutput.portalIfc.indications, lMemServerIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerRequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MemServerRequestS2H)), lMemServerRequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);

   Axi4SlaveLiteBits#(32,32) oclSlave <- mkAxi4SlaveLiteBitsFromPhysMemSlave(top.slave, clocked_by defaultClock, reset_by defaultReset);

   interface AwsF1ClSh cl_sh;
      method id0 = 32'hF000_1D0F; // 32'hc100_1be7;
      method id1 = 32'h1D51_FEDD; // 32'hc101_1be7;
   endinterface

   interface ocl = oclSlave;

`ifdef PinType
   interface pins = top.pins;
`endif
endmodule

// Copyright (c) 2017 Connectal Project

// 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 ConnectalConfig::*;
import Vector            :: *;
import GetPut::*;
import Connectable::*;
import Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes:: *;
import MMU:: *;
import MemServer:: *;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import SimDma::*;
import IfcNames::*;
import BuildVector::*;
import AxiBits::*;
import FIFOF::*;
import CFFIFO::*;

`include "ConnectalProjectConfig.bsv"

`ifdef PinTypeInclude
import `PinTypeInclude::*;
`endif
`ifdef PinType
typedef `PinType PinType;
`else
typedef Empty PinType;
`endif

(* always_enabled, always_ready *)
interface AwsF1ClSh;
   method Bit#(1) flr_done();
   method Bit#(32) status0();
   method Bit#(32) status1();
   method Bit#(32) id0();
   method Bit#(32) id1();
   method Bit#(16) status_vled();
endinterface

(* always_enabled, always_ready *)
interface AwsF1ShCl;
   (* prefix="" *)
   method Action flr_assert(Bit#(1) flr_assert);
   (* prefix="" *)
   method Action ctl0(Bit#(32) ctl0);
   (* prefix="" *)
   method Action ctl1(Bit#(32) ctl1);
   (* prefix="" *)
   method Action status_vdip(Bit#(16) status_vdip);
   (* prefix="" *)
   method Action pwr_state(Bit#(2) pwr_state);
endinterface

interface AwsF1Top;
   interface PinType pins;
   interface AwsF1ShCl sh_cl;
   interface AwsF1ClSh cl_sh;
   interface Axi4SlaveBits#(64,512,6,Empty) dmasink;
   interface Axi4SlaveLiteBits#(32,32) ocl;
   interface Axi4SlaveLiteBits#(32,32) sda;
   interface Axi4SlaveLiteBits#(32,32) bar1;
endinterface

module mkAxi4SlaveLiteBitsFromPhysMemSlave#(PhysMemSlave#(addrWidth,dataWidth) slave)
       (Axi4SlaveLiteBits#(axiaddrWidth,dataWidth)) provisos (Div#(dataWidth,8,burstLen),Add#(addrWidth,a__,axiaddrWidth));

    let burstLen = fromInteger(valueOf(burstLen));

    Wire#(Bit#(addrWidth)) araddrWire <- mkDWire(0);
    Wire#(Bit#(1)) arvalidWire <- mkDWire(0);
    Wire#(Bit#(1)) rreadyWire <- mkDWire(0);
    Wire#(Bit#(dataWidth)) rdataWire <- mkDWire(0);

    Wire#(Bit#(addrWidth)) awaddrWire <- mkDWire(0);
    Wire#(Bit#(1)) awvalidWire <- mkDWire(0);
    Wire#(Bit#(1)) wvalidWire <- mkDWire(0);
    Wire#(Bit#(dataWidth)) wdataWire <- mkDWire(0);
    Wire#(Bit#(1)) breadyWire <- mkDWire(0);

    FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arFifo <- mkCFFIFOF();
    FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awFifo <- mkCFFIFOF();
    FIFOF#(MemData#(dataWidth)) rdataFifo <- mkCFFIFOF();
    FIFOF#(MemData#(dataWidth)) wdataFifo <- mkCFFIFOF();
    FIFOF#(Bit#(MemTagSize)) brespFifo <- mkCFFIFOF();

    rule ar_rule if (arvalidWire == 1 && arFifo.notFull());
       let req = PhysMemRequest {addr: araddrWire, burstLen: burstLen, tag: 0 };
       arFifo.enq(req);
    endrule
    rule ar_to_slave;
       let req <- toGet(arFifo).get();
       slave.read_server.readReq.put(req);
    endrule

    rule aw_rule if (awvalidWire == 1 && awFifo.notFull());
       let req = PhysMemRequest {addr: awaddrWire, burstLen: burstLen, tag: 0 };
       awFifo.enq(req);
    endrule
    rule aw_to_slave;
       let req <- toGet(awFifo).get();
       slave.read_server.readReq.put(req);
    endrule

    rule r_rule if (rreadyWire == 1 && rdataFifo.notEmpty());
       rdataFifo.deq();
    endrule
    rule rdata_from_slave;
       let mdata <- slave.read_server.readData.get();
       rdataFifo.enq(mdata);
    endrule

    rule wdata_rule if (wvalidWire == 1 && wdataFifo.notFull());
       wdataFifo.enq(MemData { data: wdataWire, tag: 0, last: True });
    endrule
    rule wdata_to_slave;
       let mdata <- toGet(wdataFifo).get();
       slave.write_server.writeData.put(mdata);
    endrule

    rule b_rule if (breadyWire == 1 && brespFifo.notEmpty());
       brespFifo.deq();
    endrule
    rule bresp_from_slave;
       let done <- slave.write_server.writeDone.get();
       brespFifo.enq(done);
    endrule

    method Action      araddr(Bit#(axiaddrWidth) v);
       araddrWire <= truncate(v);
    endmethod
    method Bit#(1)     arready();
       return pack(arFifo.notFull());
    endmethod
    method Action      arvalid(Bit#(1) v);
       arvalidWire <= v;
    endmethod
    method Action      awaddr(Bit#(axiaddrWidth) v);
       awaddrWire <= truncate(v);
    endmethod
    method Bit#(1)     awready();
       return pack(awFifo.notFull());
    endmethod
    method Action      awvalid(Bit#(1) v);
       awvalidWire <= v;
    endmethod
    method Action      bready(Bit#(1) v);
       breadyWire <= v;
    endmethod
    method Bit#(2)     bresp();
       return 0; // brespFifo.first();
    endmethod
    method Bit#(1)     bvalid();
       return pack(brespFifo.notEmpty());
    endmethod
    method Bit#(dataWidth)     rdata();
       return rdataFifo.first.data;
    endmethod
    method Action      rready(Bit#(1) v);
       rreadyWire <= v;
    endmethod
    method Bit#(2)     rresp();
       return 0;
    endmethod
    method Bit#(1)     rvalid();
      return pack(rdataFifo.notEmpty);
    endmethod
    method Action      wdata(Bit#(dataWidth) v);
       wdataWire <= v;
    endmethod
    method Bit#(1)     wready();
       return pack(wdataFifo.notFull());
    endmethod
    method Action      wvalid(Bit#(1) v);
       wvalidWire <= v;
    endmethod
endmodule

(* no_default_clock, no_default_reset, clock_prefix="", reset_prefix="" *)
module mkAwsF1Top#(Clock clk_main_a0, Clock clk_extra_a1, Clock clk_extra_a2, Clock clk_extra_a3,
       Clock  clk_extra_b0, Clock clk_extra_b1, Clock clk_extra_c0, Clock clk_extra_c1,
       Reset kernel_rst_n, Reset rst_main_n
       )(AwsF1Top);

   Clock defaultClock = clk_main_a0;
   Reset defaultReset = rst_main_n;
   Clock derivedClock = clk_main_a0;
   Reset derivedReset = rst_main_n;

   XsimHost host <- mkXsimHost(clk_main_a0, rst_main_n, clk_main_a0);
   let top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`else
`ifdef IMPORT_HOST_CLOCKS // enables synthesis boundary
       derivedClock, derivedReset,
`else
// otherwise no params
`endif
`endif
	clocked_by defaultClock, reset_by defaultReset
       );

   MMUIndicationOutput lMMUIndicationOutput <- mkMMUIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MMURequestInput lMMURequestInput <- mkMMURequestInput(clocked_by defaultClock, reset_by defaultReset);
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMMURequestInput.pipes, lMMU.request, clocked_by defaultClock, reset_by defaultReset);

   MemServerIndicationOutput lMemServerIndicationOutput <- mkMemServerIndicationOutput(clocked_by defaultClock, reset_by defaultReset);
   MemServerRequestInput lMemServerRequestInput <- mkMemServerRequestInput(clocked_by defaultClock, reset_by defaultReset);
   MemServer::MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(top.readers, top.writers, cons(lMMU,nil), lMemServerIndicationOutput.ifc, clocked_by defaultClock, reset_by defaultReset);
   mkConnection(lMemServerRequestInput.pipes, lMemServer.request, clocked_by defaultClock, reset_by defaultReset);

   let lMMUIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MMUIndicationH2S)), lMMUIndicationOutput.portalIfc.indications, lMMUIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMMURequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MMURequestS2H)), lMMURequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerIndicationOutputNoc <- mkPortalMsgIndication(extend(pack(PlatformIfcNames_MemServerIndicationH2S)), lMemServerIndicationOutput.portalIfc.indications, lMemServerIndicationOutput.portalIfc.messageSize, clocked_by defaultClock, reset_by defaultReset);
   let lMemServerRequestInputNoc <- mkPortalMsgRequest(extend(pack(PlatformIfcNames_MemServerRequestS2H)), lMemServerRequestInput.portalIfc.requests, clocked_by defaultClock, reset_by defaultReset);

   Axi4SlaveLiteBits#(32,32) oclSlave <- mkAxi4SlaveLiteBitsFromPhysMemSlave(top.slave, clocked_by defaultClock, reset_by defaultReset);

   interface AwsF1ClSh cl_sh;
      method id0 = 32'hF000_1D0F; // 32'hc100_1be7;
      method id1 = 32'h1D51_FEDD; // 32'hc101_1be7;
   endinterface

   interface ocl = oclSlave;

`ifdef PinType
   interface pins = top.pins;
`endif
endmodule


updated Rbm.bsv so it compiles

updated Rbm.bsv so it compiles

Change-Id: I2ea074647618fc39f5f82f252268dcd74195f581

// 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 FIFO::*;
import FIFOF::*;
import DefaultValue::*;
import GetPut::*;
import ClientServer::*;
import Connectable::*;
import FloatingPoint::*;
import BRAM::*;

import PortalMemory::*;
import MemTypes::*;
import DmaVector::*;
import AxiMasterSlave::*;

import Matrix::*;
import Sigmoid::*;
import FloatOps::*;
import Pipe::*;
import Timer::*;
import RbmTypes::*;

function Float tokenValue(Token v) = v.v;

function ObjectReadClient#(asz) getSourceReadClient(DmaVectorSource#(asz,a) s); return s.dmaClient; endfunction
function ObjectWriteClient#(asz) getSinkWriteClient(DmaVectorSink#(asz,a) s); return s.dmaClient; endfunction

interface DmaStatesPipe#(numeric type n, numeric type dmasz);
   interface Vector#(1, ObjectReadClient#(dmasz)) sources;
   interface Vector#(1, ObjectWriteClient#(dmasz)) sinks;
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
   method ActionValue#(Bool) finish();
endinterface

(* synthesize *)
module  mkDmaStatesPipe(DmaStatesPipe#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   DmaVectorSource#(DmaSz, Vector#(N,Float)) statesource <- mkDmaVectorSource();
   PipeOut#(Vector#(N, Float)) dmaStatesPipe <- mkComputeStatesPipe(statesource.vector.pipe);
   DmaVectorSink#(DmaSz, Vector#(N, Float)) dmaStatesSink <- mkDmaVectorSink(dmaStatesPipe);

   interface Vector sources = cons(statesource.dmaClient, nil);
   interface Vector sinks = cons(dmaStatesSink.dmaClient, nil);
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
				  Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
      statesource.vector.start(readPointer, extend(readOffset), extend(unpack(numElts)));
      dmaStatesSink.vector.start(writePointer, extend(writeOffset), extend(unpack(numElts)));
   endmethod
   method ActionValue#(Bool) finish();
      let b <- dmaStatesSink.vector.finish();
      return b;
   endmethod
endmodule

interface DmaStatesPipe2#(numeric type n, numeric type dmasz);
   interface Vector#(2, ObjectReadClient#(dmasz))  sources;
   interface Vector#(1, ObjectWriteClient#(dmasz)) sinks;
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
   method ActionValue#(Bool) finish();
endinterface

(* synthesize *)
module  mkDmaStatesPipe2(DmaStatesPipe2#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   Vector#(2, DmaVectorSource#(DmaSz, Vector#(N,Float))) statesources <- replicateM(mkDmaVectorSource());
   PipeOut#(Vector#(N, Float)) dmaStatesPipe <- mkComputeStatesPipe2(statesources[0].vector.pipe, statesources[1].vector.pipe);
   DmaVectorSink#(DmaSz, Vector#(N, Float)) dmaStatesSink <- mkDmaVectorSink(dmaStatesPipe);

   interface Vector sources = map(getSourceReadClient, statesources);
   interface Vector sinks = cons(dmaStatesSink.dmaClient, nil);
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
      statesources[0].vector.start(readPointer, extend(readOffset), extend(unpack(numElts)));
      statesources[1].vector.start(readPointer2, extend(readOffset2), extend(unpack(numElts)));
      dmaStatesSink.vector.start(writePointer, extend(writeOffset), extend(unpack(numElts)));
   endmethod
   method ActionValue#(Bool) finish();
      let b <- dmaStatesSink.vector.finish();
      return b;
   endmethod
endmodule

interface DmaUpdateWeights#(numeric type n, numeric type dmasz);
   interface Vector#(3, ObjectReadClient#(dmasz)) readClients;
   interface Vector#(1, ObjectWriteClient#(dmasz)) writeClients;
   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Float learningRateOverNumExamples);
   method ActionValue#(Bool) finish();
endinterface

(* synthesize *)
module  mkDmaUpdateWeights(DmaUpdateWeights#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   Vector#(3, DmaVectorSource#(DmaSz, Vector#(N,Float))) sources <- replicateM(mkDmaVectorSource());

   let n = valueOf(N);

   Reg#(Float) learningRateOverNumExamples <- mkReg(defaultValue);

   FIFOF#(Vector#(N,Float)) wfifo <- mkFIFOF();
   Vector#(N, FloatAlu) adders <- replicateM(mkFloatAdder(defaultValue));
   Vector#(N, FloatAlu) adders2 <- replicateM(mkFloatAdder(defaultValue));
   Vector#(N, FloatAlu) multipliers <- replicateM(mkFloatMultiplier(defaultValue));
   DmaVectorSink#(DmaSz, Vector#(N, Float)) sink <- mkDmaVectorSink(toPipeOut(wfifo));

// weights += learningRate * (pos_associations - neg_associations) / num_examples;
   rule sub;
      let pa = sources[0].vector.pipe.first();
      sources[0].vector.pipe.deq();
      let na = sources[1].vector.pipe.first();
      sources[1].vector.pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 adders[i].request.put(tuple2(pa[i], -na[i]));
      end
   endrule
   rule mul;
      for (Integer i = 0; i < n; i = i+1) begin
	 let sumexc <- adders[i].response.get();
	 multipliers[i].request.put(tuple2(learningRateOverNumExamples, tpl_1(sumexc)));
      end
   endrule
   rule add;
      let weights = sources[2].vector.pipe.first();
      sources[2].vector.pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- multipliers[i].response.get();
	 adders2[i].request.put(tuple2(weights[i], tpl_1(resultexc)));
      end
   endrule
   rule result;
      Vector#(N, Float) r;
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- adders2[i].response.get();
	 r[i] = tpl_1(resultexc);
      end
      wfifo.enq(r);
   endrule

   for (Integer i = 0; i < 3; i = i + 1)
      rule finishSources;
	 let b <- sources[i].vector.finish();
      endrule

   //interface Vector sources = cons(statesource, nil);
   interface Vector readClients = map(getSourceReadClient, sources);
   interface Vector writeClients = cons(getSinkWriteClient(sink), nil);
   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Float lrone);
      learningRateOverNumExamples <= lrone;
      sources[0].vector.start(posAssociationsPointer, 0, extend(numElts));
      sources[1].vector.start(negAssociationsPointer, 0, extend(numElts));
      sources[2].vector.start(weightsPointer, 0, extend(numElts));
      sink.vector.start(weightsPointer, 0, extend(numElts));
   endmethod
   method ActionValue#(Bool) finish();
      let b <- sink.vector.finish();
      return b;
   endmethod
endmodule
interface DmaSumOfErrorSquared#(numeric type n, numeric type dmasz);
   interface Vector#(2, ObjectReadClient#(dmasz)) readClients;
   interface PipeOut#(Float) pipe;
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
endinterface

(* synthesize *)
module  mkDmaSumOfErrorSquared(DmaSumOfErrorSquared#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   Vector#(2, DmaVectorSource#(DmaSz, Vector#(N,Float))) sources <- replicateM(mkDmaVectorSource());

   let n = valueOf(N);

   let dotprod <- mkSharedDotProdServer(0);

   FirstLastPipe#(Bit#(ObjectOffsetSize)) firstlastPipe <- mkFirstLastPipe();
   PipeOut#(Float) aPipe <- mkFunnel1(sources[0].vector.pipe);
   PipeOut#(Float) bPipe <- mkFunnel1(sources[1].vector.pipe);
   let joinPipe <- mkJoin(tuple2, aPipe, bPipe);
   let subPipe <- mkFloatSubPipe(joinPipe);
   rule fromsub;
      match {.first, .last} <- toGet(firstlastPipe.pipe).get();
      let diff <- toGet(subPipe).get();
      Token t = Token { v: diff, first: first, last: last };
      dotprod.aInput.put(t);
      dotprod.bInput.put(t);
   endrule

   for (Integer i = 0; i < 2; i = i + 1)
      rule finishSources;
	 let b <- sources[i].vector.finish();
      endrule

   //interface Vector sources = cons(statesource, nil);
   interface Vector readClients = map(getSourceReadClient, sources);
   interface PipeOut pipe = mapPipe(tokenValue, dotprod.pipes[0]);
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
      sources[0].vector.start(dataPointer, 0, extend(numElts));
      sources[1].vector.start(predPointer, 0, extend(numElts));
      firstlastPipe.start(extend(numElts));
   endmethod
endmodule: mkDmaSumOfErrorSquared

interface Rbm#(numeric type n);
   interface RbmRequest rbmRequest;
   interface MmRequest mmRequest;
   interface MmDebugRequest mmDebugRequest;
   interface SigmoidRequest sigmoidRequest;
   interface TimerRequest timerRequest;
   interface Vector#(12, ObjectReadClient#(TMul#(32,n))) readClients;
   interface Vector#(5, ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module  mkRbm#(RbmIndication rbmInd, MmIndication mmInd, MmDebugIndication mmDebugInd, SigmoidIndication sigmoidInd, TimerIndication timerInd)(Rbm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz)
      );

   let n = valueOf(n);

   Mm#(N) mm <- mkMm(mmInd, timerInd, mmDebugInd);

   DmaSigmoidIfc#(TMul#(32,n)) dmaSigmoid <- mkDmaSigmoid();
   Vector#(2,ObjectReadClient#(TMul#(32,n))) sigmoidsources = dmaSigmoid.readClients;

   DmaStatesPipe#(N, DmaSz) dmaStates <- mkDmaStatesPipe();
   DmaStatesPipe2#(N, DmaSz) dmaStates2 <- mkDmaStatesPipe2();

   DmaUpdateWeights#(N, DmaSz) dmaUpdateWeights <- mkDmaUpdateWeights();
   DmaSumOfErrorSquared#(N, DmaSz) dmaSumOfErrorSquared <- mkDmaSumOfErrorSquared();

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   rule sigmoidDone;
      $display("sigmoidDone");
      let d <- dmaSigmoid.finish();
      busyFifo.deq();
      sigmoidInd.sigmoidDone();
   endrule
   rule sigmoidTableUpdateDone;
      $display("sigmoidDone");
      let d <- dmaSigmoid.sigmoidTableUpdated();
      busyFifo.deq();
      sigmoidInd.sigmoidTableUpdated(0);
   endrule
   rule dmaStatesDone;
      $display("dmaStatesDone");
      let b <- dmaStates.finish();
      busyFifo.deq();
      rbmInd.statesDone();
   endrule
   rule dmaStatesDone2;
      $display("dmaStatesDone2");
      let b <- dmaStates2.finish();
      busyFifo.deq();
      rbmInd.statesDone2();
   endrule

   rule dmaUpdateWeightsDone;
      $display("dmaUpdateWeightsDone");
      let b <- dmaUpdateWeights.finish();
      busyFifo.deq();
      rbmInd.updateWeightsDone();
   endrule

   rule dmaSumOfErrorSquaredDone;
      $display("dmaSumOfErrorSquaredDone");
      dmaSumOfErrorSquared.pipe.deq();
      busyFifo.deq();
      rbmInd.sumOfErrorSquared(pack(dmaSumOfErrorSquared.pipe.first()));
   endrule

   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   interface TimerRequest timerRequest;
         method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface

   interface MmRequest mmRequest = mm.mmRequest;
   interface MmDebugRequest mmDebugRequest = mm.mmDebug;

   interface SigmoidRequest sigmoidRequest;
      method Action sigmoid(Bit#(32) readPointer, Bit#(32) readOffset,
			    Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 dmaSigmoid.start(readPointer, writePointer, unpack(extend(numElts)));
	 busyFifo.enq(True);
      endmethod
      method Action setSigmoidLimits(Bit#(32) rscale, Bit#(32) llimit, Bit#(32) ulimit);
	 $display("rbm.setSigmoidLimits");
	 dmaSigmoid.setSigmoidLimits(unpack(rscale), unpack(llimit), unpack(ulimit));
	 busyFifo.enq(True);
      endmethod
      method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
	 $display("rbm.updateSigmoidTable pointer=%x addr=%h numElts=%d", readPointer, readOffset, numElts);
	 dmaSigmoid.updateSigmoidTable(readPointer, extend(readOffset), extend(numElts));
	 busyFifo.enq(True);
      endmethod
      method Action sigmoidTableSize();
	 sigmoidInd.sigmoidTableSize(dmaSigmoid.tableSize());
      endmethod
   endinterface

   interface RbmRequest rbmRequest;
      method Action bramMmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			    Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			    Bit#(32) h3);
	 // bramMMF.start(h1, unpack(extend(r1)), unpack(extend(c1)),
	 // 	       h2, unpack(extend(r2)), unpack(extend(c2)),
	 // 	       h3);
	 // busyFifo.enq(True);
      endmethod
      method Action toBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);
	 // bramMMF.toBram(off, pointer, offset, numElts);
	 // busyFifo.enq(True);
      endmethod

      method Action fromBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);
	 // bramMMF.fromBram(off, pointer, offset, numElts);
	 // busyFifo.enq(True);
      endmethod

      method Action dbg();
      endmethod

      method Action finish();
	 $finish(0);
      endmethod
      method Action computeStates(Bit#(32) readPointer, Bit#(32) readOffset,
				  Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 //$display("computeStates rh=%d wh=%d len=%d", readPointer, writePointer, numElts);
	 dmaStates.start(readPointer, readOffset,
			 writePointer, writeOffset, numElts);
	 busyFifo.enq(True);
      endmethod
      method Action computeStates2(Bit#(32) readPointer, Bit#(32) readOffset,
				   Bit#(32) readPointer2, Bit#(32) readOffset2,
				   Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 //$display("computeStates2 rh=%d wh=%d len=%d", readPointer, writePointer, numElts);
	 dmaStates2.start(readPointer, readOffset,
			  readPointer2, readOffset2,
			  writePointer,writeOffset, numElts);

	 busyFifo.enq(True);
      endmethod
      method Action updateWeights(Bit#(32) posAssociationsPointer,
	 Bit#(32) negAssociationsPointer,
				  Bit#(32) weightsPointer,
				  Bit#(32) numElts,
				  Bit#(32) learningRateOverNumExamples);
	 dmaUpdateWeights.start(posAssociationsPointer, negAssociationsPointer, weightsPointer,
				numElts, unpack(learningRateOverNumExamples));
	 busyFifo.enq(True);
      endmethod
      method Action sumOfErrorSquared(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
	 dmaSumOfErrorSquared.start(dataPointer, predPointer, numElts);
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface Vector readClients = append(
					 //append(
					    mm.readClients,
					    //bramMMF.readClients
					    //),
					 append(
						append(dmaUpdateWeights.readClients,
						       dmaSumOfErrorSquared.readClients),
						append(
						   sigmoidsources,
						   append(
						      dmaStates.sources,
						      dmaStates2.sources)
						   )));

   interface Vector writeClients =
      append(dmaUpdateWeights.writeClients,
	     cons(dmaSigmoid.dmaClient, cons(dmaStates.sinks[0], cons(dmaStates2.sinks[0],
								      cons(mm.writeClient, nil)))));
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 FIFO::*;
import FIFOF::*;
import DefaultValue::*;
import GetPut::*;
import ClientServer::*;
import Connectable::*;
import FloatingPoint::*;
import BRAM::*;

import AxiDma::*;
import PortalMemory::*;
import Dma::*;
import DmaVector::*;
import AxiMasterSlave::*;

import Matrix::*;
import Sigmoid::*;
import FloatOps::*;
import Pipe::*;
import Timer::*;
import RbmTypes::*;

function ObjectReadClient#(asz) getSourceReadClient(DmaVectorSource#(asz,a) s); return s.dmaClient; endfunction
function ObjectWriteClient#(asz) getSinkWriteClient(DmaVectorSink#(asz,a) s); return s.dmaClient; endfunction

interface DmaStatesPipe#(numeric type n, numeric type dmasz);
   interface Vector#(1, ObjectReadClient#(dmasz)) sources;
   interface Vector#(1, ObjectWriteClient#(dmasz)) sinks;
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
   method ActionValue#(Bool) finish();
endinterface

(* synthesize *)
module  mkDmaStatesPipe(DmaStatesPipe#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   DmaVectorSource#(DmaSz, Vector#(N,Float)) statesource <- mkDmaVectorSource();
   PipeOut#(Vector#(N, Float)) dmaStatesPipe <- mkComputeStatesPipe(statesource.vector.pipe);
   DmaVectorSink#(DmaSz, Vector#(N, Float)) dmaStatesSink <- mkDmaVectorSink(dmaStatesPipe);

   interface Vector sources = cons(statesource.dmaClient, nil);
   interface Vector sinks = cons(dmaStatesSink.dmaClient, nil);
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
				  Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
      statesource.vector.start(readPointer, extend(readOffset), extend(unpack(numElts)));
      dmaStatesSink.vector.start(writePointer, extend(writeOffset), extend(unpack(numElts)));
   endmethod
   method ActionValue#(Bool) finish();
      let b <- dmaStatesSink.vector.finish();
      return b;
   endmethod
endmodule

interface DmaStatesPipe2#(numeric type n, numeric type dmasz);
   interface Vector#(2, ObjectReadClient#(dmasz))  sources;
   interface Vector#(1, ObjectWriteClient#(dmasz)) sinks;
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
   method ActionValue#(Bool) finish();
endinterface

(* synthesize *)
module  mkDmaStatesPipe2(DmaStatesPipe2#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   Vector#(2, DmaVectorSource#(DmaSz, Vector#(N,Float))) statesources <- replicateM(mkDmaVectorSource());
   PipeOut#(Vector#(N, Float)) dmaStatesPipe <- mkComputeStatesPipe2(statesources[0].vector.pipe, statesources[1].vector.pipe);
   DmaVectorSink#(DmaSz, Vector#(N, Float)) dmaStatesSink <- mkDmaVectorSink(dmaStatesPipe);

   interface Vector sources = map(getSourceReadClient, statesources);
   interface Vector sinks = cons(dmaStatesSink.dmaClient, nil);
   method Action start(Bit#(32) readPointer, Bit#(32) readOffset,
		       Bit#(32) readPointer2, Bit#(32) readOffset2,
		       Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
      statesources[0].vector.start(readPointer, extend(readOffset), extend(unpack(numElts)));
      statesources[1].vector.start(readPointer2, extend(readOffset2), extend(unpack(numElts)));
      dmaStatesSink.vector.start(writePointer, extend(writeOffset), extend(unpack(numElts)));
   endmethod
   method ActionValue#(Bool) finish();
      let b <- dmaStatesSink.vector.finish();
      return b;
   endmethod
endmodule

interface DmaUpdateWeights#(numeric type n, numeric type dmasz);
   interface Vector#(3, ObjectReadClient#(dmasz)) readClients;
   interface Vector#(1, ObjectWriteClient#(dmasz)) writeClients;
   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Float learningRateOverNumExamples);
   method ActionValue#(Bool) finish();
endinterface

(* synthesize *)
module  mkDmaUpdateWeights(DmaUpdateWeights#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   Vector#(3, DmaVectorSource#(DmaSz, Vector#(N,Float))) sources <- replicateM(mkDmaVectorSource());

   let n = valueOf(N);

   Reg#(Float) learningRateOverNumExamples <- mkReg(defaultValue);

   FIFOF#(Vector#(N,Float)) wfifo <- mkFIFOF();
   Vector#(N, FloatServer2#(Float)) adders <- replicateM(mkFloatAdder());
   Vector#(N, FloatServer2#(Float)) adders2 <- replicateM(mkFloatAdder());
   Vector#(N, FloatServer2#(Float)) multipliers <- replicateM(mkFloatMultiplier());
   DmaVectorSink#(DmaSz, Vector#(N, Float)) sink <- mkDmaVectorSink(toPipeOut(wfifo));

// weights += learningRate * (pos_associations - neg_associations) / num_examples;
   rule sub;
      let pa = sources[0].vector.pipe.first();
      sources[0].vector.pipe.deq();
      let na = sources[1].vector.pipe.first();
      sources[1].vector.pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 adders[i].request.put(tuple3(pa[i], -na[i], defaultValue));
      end
   endrule
   rule mul;
      for (Integer i = 0; i < n; i = i+1) begin
	 let sumexc <- adders[i].response.get();
	 multipliers[i].request.put(tuple3(learningRateOverNumExamples, tpl_1(sumexc), defaultValue));
      end
   endrule
   rule add;
      let weights = sources[2].vector.pipe.first();
      sources[2].vector.pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- multipliers[i].response.get();
	 adders2[i].request.put(tuple3(weights[i], tpl_1(resultexc), defaultValue));
      end
   endrule
   rule result;
      Vector#(N, Float) r;
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- adders2[i].response.get();
	 r[i] = tpl_1(resultexc);
      end
      wfifo.enq(r);
   endrule

   for (Integer i = 0; i < 3; i = i + 1)
      rule finishSources;
	 let b <- sources[i].vector.finish();
      endrule

   //interface Vector sources = cons(statesource, nil);
   interface Vector readClients = map(getSourceReadClient, sources);
   interface Vector writeClients = cons(getSinkWriteClient(sink), nil);
   method Action start(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Float lrone);
      learningRateOverNumExamples <= lrone;
      sources[0].vector.start(posAssociationsPointer, 0, extend(numElts));
      sources[1].vector.start(negAssociationsPointer, 0, extend(numElts));
      sources[2].vector.start(weightsPointer, 0, extend(numElts));
      sink.vector.start(weightsPointer, 0, extend(numElts));
   endmethod
   method ActionValue#(Bool) finish();
      let b <- sink.vector.finish();
      return b;
   endmethod
endmodule
interface DmaSumOfErrorSquared#(numeric type n, numeric type dmasz);
   interface Vector#(2, ObjectReadClient#(dmasz)) readClients;
   interface PipeOut#(Float) pipe;
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
endinterface

(* synthesize *)
module  mkDmaSumOfErrorSquared(DmaSumOfErrorSquared#(N, DmaSz))
   provisos (Bits#(Vector#(N, Float), DmaSz)
	     );
   Vector#(2, DmaVectorSource#(DmaSz, Vector#(N,Float))) sources <- replicateM(mkDmaVectorSource());

   let n = valueOf(N);

   Reg#(Bit#(32)) resultCount <- mkReg(0);
   Vector#(N, FloatServer2#(Float)) adders <- replicateM(mkFloatAdder());
   Vector#(N, Server#(Tuple4#(Maybe#(Float), Float, Float, RoundMode), Tuple2#(Float,Exception))) macs <- replicateM(mkFloatMac());
   FIFOF#(Vector#(N, Float)) accfifo <- mkFIFOF();
   FIFOF#(Vector#(N, Float)) resultFifo <- mkFIFOF();

   // compute sum((data - pred)^2)

   rule sub;
      let data = sources[0].vector.pipe.first();
      sources[0].vector.pipe.deq();
      let pred = sources[1].vector.pipe.first();
      sources[1].vector.pipe.deq();
      for (Integer i = 0; i < n; i = i+1) begin
	 adders[i].request.put(tuple3(data[i], -pred[i], defaultValue));
      end
   endrule
   rule mac;
      let sum = accfifo.first;
      accfifo.deq;
      for (Integer i = 0; i < n; i = i+1) begin
	 let sumexc <- adders[i].response.get();
	 macs[i].request.put(tuple4(tagged Valid sum[i], tpl_1(sumexc), tpl_1(sumexc), defaultValue));
      end
   endrule
   rule acc if (resultCount > 0);
      Vector#(N, Float) sum = replicate(defaultValue);
      for (Integer i = 0; i < n; i = i+1) begin
	 let resultexc <- macs[i].response.get();
	 sum[i] = tpl_1(resultexc);
      end
      if (resultCount > 1)
	 accfifo.enq(sum);
      else
	 resultFifo.enq(sum);
      resultCount <= resultCount - 1;
   endrule

   PipeOut#(Vector#(N, Float)) sumPipe = toPipeOut(resultFifo);
   PipeOut#(Float) foldedPipe <- mkReducePipe(mkFloatAddPipe, sumPipe);

   for (Integer i = 0; i < 2; i = i + 1)
      rule finishSources;
	 let b <- sources[i].vector.finish();
      endrule

   //interface Vector sources = cons(statesource, nil);
   interface Vector readClients = map(getSourceReadClient, sources);
   interface PipeOut pipe = foldedPipe;
   method Action start(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts) if (resultCount == 0);
      sources[0].vector.start(dataPointer, 0, extend(numElts));
      sources[1].vector.start(predPointer, 0, extend(numElts));
      Vector#(N, Float) sum = replicate(fromReal(0.0));
      accfifo.enq(sum);

      resultCount <= numElts;
   endmethod
endmodule

interface Rbm#(numeric type n);
   interface RbmRequest rbmRequest;
   interface MmRequest mmRequest;
   interface SigmoidRequest sigmoidRequest;
   interface TimerRequest timerRequest;
   interface Vector#(TAdd#(11,N), ObjectReadClient#(TMul#(32,n))) readClients;
   interface Vector#(5, ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module  mkRbm#(RbmIndication rbmInd, MmIndication mmInd, SigmoidIndication sigmoidInd, TimerIndication timerInd)(Rbm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz)
      );

   let n = valueOf(n);

   DramMatrixMultiply#(N, TMul#(N,32)) dmaMMF <- mkDramMatrixMultiply();
   //DramBramMatrixMultiply#(N, TMul#(N,32)) bramMMF <- mkDramBramMatrixMultiply();

   DmaSigmoidIfc#(TMul#(32,n)) dmaSigmoid <- mkDmaSigmoid();
   Vector#(2,ObjectReadClient#(TMul#(32,n))) sigmoidsources = dmaSigmoid.readClients;

   DmaStatesPipe#(N, DmaSz) dmaStates <- mkDmaStatesPipe();
   DmaStatesPipe2#(N, DmaSz) dmaStates2 <- mkDmaStatesPipe2();

   DmaUpdateWeights#(N, DmaSz) dmaUpdateWeights <- mkDmaUpdateWeights();
   DmaSumOfErrorSquared#(N, DmaSz) dmaSumOfErrorSquared <- mkDmaSumOfErrorSquared();

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   rule mmfDone;
      $display("mmfDone");
      let d <- dmaMMF.finish();
      busyFifo.deq();
      mmInd.mmfDone();
   endrule
   rule sigmoidDone;
      $display("sigmoidDone");
      let d <- dmaSigmoid.finish();
      busyFifo.deq();
      sigmoidInd.sigmoidDone();
   endrule
   rule sigmoidTableUpdateDone;
      $display("sigmoidDone");
      let d <- dmaSigmoid.sigmoidTableUpdated();
      busyFifo.deq();
      sigmoidInd.sigmoidTableUpdated(0);
   endrule
   rule dmaStatesDone;
      $display("dmaStatesDone");
      let b <- dmaStates.finish();
      busyFifo.deq();
      rbmInd.statesDone();
   endrule
   rule dmaStatesDone2;
      $display("dmaStatesDone2");
      let b <- dmaStates2.finish();
      busyFifo.deq();
      rbmInd.statesDone2();
   endrule

   rule dmaUpdateWeightsDone;
      $display("dmaUpdateWeightsDone");
      let b <- dmaUpdateWeights.finish();
      busyFifo.deq();
      rbmInd.updateWeightsDone();
   endrule

   rule dmaSumOfErrorSquaredDone;
      $display("dmaSumOfErrorSquaredDone");
      dmaSumOfErrorSquared.pipe.deq();
      busyFifo.deq();
      rbmInd.sumOfErrorSquared(pack(dmaSumOfErrorSquared.pipe.first()));
   endrule

   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   interface TimerRequest timerRequest;
         method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface

   interface MmRequest mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3);
	 dmaMMF.start(h1, unpack(extend(r1)), unpack(extend(c1)),
		      h2, unpack(extend(r2)), unpack(extend(c2)),
		      h3);
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface SigmoidRequest sigmoidRequest;
      method Action sigmoid(Bit#(32) readPointer, Bit#(32) readOffset,
			    Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 dmaSigmoid.start(readPointer, writePointer, unpack(extend(numElts)));
	 busyFifo.enq(True);
      endmethod
      method Action setSigmoidLimits(Bit#(32) rscale, Bit#(32) llimit, Bit#(32) ulimit);
	 $display("rbm.setSigmoidLimits");
	 dmaSigmoid.setSigmoidLimits(unpack(rscale), unpack(llimit), unpack(ulimit));
	 busyFifo.enq(True);
      endmethod
      method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
	 $display("rbm.updateSigmoidTable pointer=%x addr=%h numElts=%d", readPointer, readOffset, numElts);
	 dmaSigmoid.updateSigmoidTable(readPointer, extend(readOffset), extend(numElts));
	 busyFifo.enq(True);
      endmethod
      method Action sigmoidTableSize();
	 sigmoidInd.sigmoidTableSize(dmaSigmoid.tableSize());
      endmethod
   endinterface

   interface RbmRequest rbmRequest;
      method Action bramMmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			    Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			    Bit#(32) h3);
	 // bramMMF.start(h1, unpack(extend(r1)), unpack(extend(c1)),
	 // 	       h2, unpack(extend(r2)), unpack(extend(c2)),
	 // 	       h3);
	 // busyFifo.enq(True);
      endmethod
      method Action toBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);
	 // bramMMF.toBram(off, pointer, offset, numElts);
	 // busyFifo.enq(True);
      endmethod

      method Action fromBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);
	 // bramMMF.fromBram(off, pointer, offset, numElts);
	 // busyFifo.enq(True);
      endmethod

      method Action dbg();
      endmethod

      method Action finish();
	 $finish(0);
      endmethod
      method Action computeStates(Bit#(32) readPointer, Bit#(32) readOffset,
				  Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 //$display("computeStates rh=%d wh=%d len=%d", readPointer, writePointer, numElts);
	 dmaStates.start(readPointer, readOffset,
			 writePointer, writeOffset, numElts);
	 busyFifo.enq(True);
      endmethod
      method Action computeStates2(Bit#(32) readPointer, Bit#(32) readOffset,
				   Bit#(32) readPointer2, Bit#(32) readOffset2,
				   Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
	 //$display("computeStates2 rh=%d wh=%d len=%d", readPointer, writePointer, numElts);
	 dmaStates2.start(readPointer, readOffset,
			  readPointer2, readOffset2,
			  writePointer,writeOffset, numElts);

	 busyFifo.enq(True);
      endmethod
      method Action updateWeights(Bit#(32) posAssociationsPointer,
	 Bit#(32) negAssociationsPointer,
				  Bit#(32) weightsPointer,
				  Bit#(32) numElts,
				  Bit#(32) learningRateOverNumExamples);
	 dmaUpdateWeights.start(posAssociationsPointer, negAssociationsPointer, weightsPointer,
				numElts, unpack(learningRateOverNumExamples));
	 busyFifo.enq(True);
      endmethod
      method Action sumOfErrorSquared(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);
	 dmaSumOfErrorSquared.start(dataPointer, predPointer, numElts);
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface Vector readClients = append(
					 //append(
					    dmaMMF.readClients,
					    //bramMMF.readClients
					    //),
					 append(
						append(dmaUpdateWeights.readClients,
						       dmaSumOfErrorSquared.readClients),
						append(
						   sigmoidsources,
						   append(
						      dmaStates.sources,
						      dmaStates2.sources)
						   )));

   interface Vector writeClients = append(
      append(dmaUpdateWeights.writeClients,
	     cons(dmaSigmoid.dmaClient, cons(dmaStates.sinks[0], cons(dmaStates2.sinks[0], nil)))),
//      append(
	 dmaMMF.writeClients //,	     bramMMF.writeClients)
      );
endmodule