pipeline computation of gather_phase

pipeline computation of gather_phase

Change-Id: I0045326cffacf0355163188ca695da9c4471adc8

// 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 MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import MemUtils::*;
import FloatingPoint::*;
import Pipe::*;
import Arith::*;
import FloatOps::*;
import Timer::*;
import RbmTypes::*;
import Assert::*;
import Connectable::*;
import Clocks::*;
import Gearbox::*;
import XilinxCells::*;
import HostInterface::*;

interface SharedDotProdDebug#(numeric type k);
   interface PipeOut#(Bit#(32)) macCount;
endinterface

interface SharedDotProdServer#(numeric type k);
   interface Put#(MmToken)                 aInput;
   interface Put#(MmToken)                 bInput;
   interface Vector#(k, PipeOut#(MmToken)) pipes;
   interface SharedDotProdDebug#(k) debug;
endinterface

typedef struct {
`ifdef TAGGED_TOKENS
   UInt#(32) row;
   UInt#(32) col;
`endif
   Float v;
   Bool first;
   Bool last;
} MmToken deriving (Eq,Bits);

typedef 8 UB_MulLat; // upper bound on MUL latency?
typedef 8 UB_AddLat; // upper bound on ADD latency?

(* synthesize *)
module  mkSharedInterleavedDotProdServer#(UInt#(TLog#(TMul#(J,K))) label)(SharedDotProdServer#(K))
   provisos(Div#(UB_AddLat,K,gatherSz));

   let ub_MulLat = valueOf(UB_MulLat);
   let ub_AddLat = valueOf(UB_AddLat);
   let kk = valueOf(K);

   Bool verbose = False; //label == 0;

   Reg#(UInt#(20)) countReg     <- mkReg(0);

   FloatAlu mul   <- mkFloatMultiplier(defaultValue);
   FloatAlu adder <- mkFloatAdder(defaultValue);
   FIFOF#(Float) adder_buffer <- mkSizedFIFOF(valueOf(TMul#(K,gatherSz)));

`ifdef TAGGED_TOKENS
   FIFO#(Tuple2#(UInt#(32),UInt#(32))) tag_fifo <- mkSizedFIFO(ub_MulLat);
   Vector#(K,Reg#(Tuple2#(UInt#(32),UInt#(32)))) tag_regs <- replicateM(mkRegU);
`endif

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

   FIFOF#(MmToken)                          afifo   <- mkFIFOF();
   PipeOut#(MmToken)                        aFunnel = toPipeOut(afifo);

   FIFOF#(MmToken)                          bfifo <- mkFIFOF();
   PipeOut#(MmToken)                        bFunnel = toPipeOut(bfifo);

   Reg#(Bit#(16)) firstCnt <- mkReg(0);
   Reg#(Bool)         gReg <- mkReg(False);
   FIFOF#(Float)     gFifo <- mkSizedFIFOF(kk);
   Reg#(Bit#(16))  lastCnt <- mkReg(0);
   Reg#(Bit#(16))gatherCnt <- mkReg(0);
   Reg#(Bool) gather_phase <- mkReg(0);
   //invariant: gather_phase = lastCnt == fromInteger(kk);

   FIFOF#(Tuple2#(Bool,Bool))    flFifo <- mkSizedFIFOF(ub_MulLat);
   Vector#(K,FIFOF#(MmToken))    dotfifos <- replicateM(mkFIFOF1);
   Reg#(Bit#(TAdd#(1,TLog#(K)))) rowReg <- mkReg(0);

   Reg#(Bit#(32)) lastMul <- mkReg(0);
   Reg#(Bit#(32)) lastAcc <- mkReg(0);
   Reg#(Bit#(32)) lastGather <- mkReg(0);
   Reg#(Bit#(32)) macs <- mkReg(0);

   (* fire_when_enabled *)
   rule connect_adder_buffer;
      match {.acc,.*} <- adder.response.get();
      adder_buffer.enq(acc);
      macs <= macs+1;
   endrule

   (* fire_when_enabled *)
   rule multiply;
      lastMul <= cycles;
      let a <- toGet(aFunnel).get();
      let b <- toGet(bFunnel).get();
      flFifo.enq(tuple2(a.first,a.last));
      if (a.first != b.first)
	 $display("****\n    Warning: a.first=%d != b.first=%d\n****", a.first, b.first);
      if (a.last != b.last)
	 $display("****\n    Warning: a.last=%d != b.last=%d\n****", a.last, b.last);
      if (verbose)
	 $display("%08d multiply: label=%d mulin first=%d last=%d", cycles-lastMul, label, a.first, a.last);
      mul.request.put(tuple2(a.v, b.v));
`ifdef TAGGED_TOKENS
      if(label==0) $display("%d (%d,%d)(%d,%d)", label, a.row, a.col, b.row, b.col);
      tag_fifo.enq(tuple2(a.row,b.col));
`endif
   endrule

   function Action incrementRowReg =
      (action
	  // I have to do this check (instead of relying on wrap-around) because
	  // rowReg has an extra bit to compenseate for bsc's silly Bit#(0) handling
	  if (rowReg+1 == fromInteger(kk)) rowReg <= 0;
	  else rowReg <= rowReg+1;
       endaction);

   (* fire_when_enabled *)
   rule accumulate if (!gather_phase);
      incrementRowReg;
      lastAcc <= cycles;
      match {.first, .last} <- toGet(flFifo).get();
      if (verbose) $display("%08d accumulate: label=%d mulout first=%d last=%d firstCnt=%d lastCnt=%d",
			    cycles-lastAcc, label, first, last, firstCnt, lastCnt);
      match {.resp,.*} <- mul.response.get;
      let acc = unpack(0);
      if (firstCnt == fromInteger(valueOf(TMul#(K,gatherSz))))
	 acc <- toGet(adder_buffer).get;
      else begin
	 firstCnt <= firstCnt+1;
      end
      adder.request.put(tuple2(resp,acc));
      if(last) begin
	 lastCnt <= lastCnt+1;
	 gather_phase <= (lastCnt == fromInteger(kk)-1);
      end
`ifdef TAGGED_TOKENS
      let row = rowReg;
      let t <- toGet(tag_fifo).get;
      tag_regs[row] <= t;
`endif
   endrule

   (* fire_when_enabled *)
   rule gather if (gather_phase);
      incrementRowReg;
      lastGather <= cycles;
      let row = rowReg;
      let last_row = row == fromInteger(kk-1);
      let last_pass = gatherCnt+1 == fromInteger(valueOf(gatherSz));
      if (verbose)
	 $display("%08d gather: gather=%d row=%d last_pass=%d last_row=%d, gReg=%d",
		  cycles-lastGather, gatherCnt, row, last_pass, last_row, gReg);
      let x <- toGet(adder_buffer).get;
      if (!last_pass) begin
	 if (last_row) begin
	    if (gReg) gatherCnt <= gatherCnt+1;
	    gReg <= !gReg;
	 end
	 if(gReg) begin
	    let y <- toGet(gFifo).get;
	    adder.request.put(tuple2(x,y));
	 end
	 else begin
	    gFifo.enq(x);
	 end
      end
      else begin
`ifdef TAGGED_TOKENS
      	 let row = tpl_1(tag_regs[row]);
      	 let col = tpl_2(tag_regs[row]);
	 dotfifos[row].enq(MmToken{row:row, col:col, v:x});
`else
	 dotfifos[row].enq(MmToken{v:x});
`endif
	 if (last_row) begin
	    gatherCnt <= 0;
	    lastCnt <= 0;
	    firstCnt <= 0;
	    gather_phase <= False;
	 end
      end
   endrule

   Vector#(K,PipeOut#(MmToken)) dotpipes = map(toPipeOut, dotfifos);

   interface Put aInput;
      method Action put(MmToken a);
   	 afifo.enq(a);
	 countReg <= countReg+1;
      endmethod
   endinterface
   interface Put bInput   = toPut(bfifo);
   interface Vector pipes = dotpipes;
   interface SharedDotProdDebug debug;
      interface PipeOut  macCount = toPipeOut(macs._read);
   endinterface
endmodule : mkSharedInterleavedDotProdServer

interface MmTileDebug;
   interface PipeOut#(Bit#(32)) macCount;
endinterface

interface MmTile;
   interface Vector#(RowsPerTile, Put#(MmToken)) aInputs;
   interface Vector#(RowsPerTile, Put#(MmToken)) bInputs;
   interface Vector#(RowsPerTile, PipeOut#(Vector#(N, MmToken))) fxPipes;
   interface MmTileDebug debug;
endinterface

function Put#(a) toCountedPut(Reg#(Bit#(n)) r, Put#(a) p);
   return (interface Put#(a);
      method Action put(a v);
	 r <= r+1;
	 p.put(v);
      endmethod
      endinterface);
endfunction

(* synthesize *)
module  mkMmTile#(Clock slowClock, Reset slowReset, UInt#(TLog#(T)) tile)(MmTile);

   let rowsPerTile = valueOf(RowsPerTile);
   let kk = valueOf(K);

   Vector#(RowsPerTile, Reg#(Bit#(32))) aMmTokensPutRegs <- replicateM(mkReg(0));
   Vector#(RowsPerTile, Reg#(Bit#(32))) bMmTokensPutRegs <- replicateM(mkReg(0));
   Vector#(RowsPerTile, Reg#(Bit#(32))) aMmTokensReadRegs <- replicateM(mkReg(0));
   Vector#(RowsPerTile, Reg#(Bit#(32))) bMmTokensReadRegs <- replicateM(mkReg(0));

   Vector#(RowsPerTile, FIFOF#(MmToken))   aFifos <- replicateM(mkFIFOF);
   Vector#(RowsPerTile, PipeOut#(MmToken)) aPipes = zipWith(toCountedPipeOut, aMmTokensReadRegs, map(toPipeOut, aFifos));
   Vector#(RowsPerTile,  FIFOF#(MmToken))   bFifos <- replicateM(mkFIFOF);
   Vector#(RowsPerTile,  PipeOut#(MmToken)) bPipes = zipWith(toCountedPipeOut, bMmTokensReadRegs, map(toPipeOut, bFifos));

   function Vector#(k,PipeOut#(MmToken)) getDotProdServerPipes(SharedDotProdServer#(k) s); return s.pipes; endfunction
   Vector#(RowsPerTile, SharedDotProdServer#(K)) fxdotprods <- mapM(mkSharedInterleavedDotProdServer, map(fromInteger,genVector));
   Vector#(RowsPerTile, Vector#(K, PipeOut#(MmToken))) fxpipes = map(getDotProdServerPipes, fxdotprods);
//`define USE_MIMO_DFIFOS // this version is faster
   let fastClock <- exposeCurrentClock();
   let fastReset <- exposeCurrentReset();
`ifndef USE_MIMO_DFIFOS
   Vector#(RowsPerTile, PipeOut#(Vector#(K, MmToken))) fxPipesK <- mapM(mkJoinVector(id), fxpipes);
   Vector#(RowsPerTile, PipeOut#(MmToken)) fxPipes1MmToken <- mapM(mkFunnel1, fxPipesK);
   Vector#(RowsPerTile, PipeOut#(Vector#(1, MmToken))) fxPipes1 = map(mapPipe(replicate), fxPipes1MmToken);
`else
   MIMOConfiguration mimoCfg = defaultValue;
   Vector#(RowsPerTile, MIMO#(K,1,TAdd#(K,1),MmToken)) dfifos <- replicateM(mkMIMO(mimoCfg));
   Vector#(RowsPerTile, PipeOut#(Vector#(1, MmToken))) fxPipes1 = map(toPipeOut, dfifos);
`endif
   Vector#(RowsPerTile, Gearbox#(1, N, MmToken)) gearboxes <- replicateM(mk1toNGearbox(fastClock, fastReset, slowClock, slowReset));
   Vector#(RowsPerTile, PipeIn#(Vector#(1,MmToken))) toGearboxes = map(toPipeIn, gearboxes);
   Vector#(RowsPerTile, PipeOut#(Vector#(N, MmToken))) fromGearboxes = map(toPipeOut, gearboxes);
   mapM(uncurry(mkConnection), zip(fxPipes1, toGearboxes));
   // introduce a buffer to help vivado meet timing on vc707
   Vector#(RowsPerTile, FIFOF#(Vector#(N,MmToken)))    tokenfifos <- replicateM(mkFIFOF(clocked_by slowClock, reset_by slowReset));
   Vector#(RowsPerTile, PipeIn#(Vector#(N,MmToken))) toMmTokenFifos = map(toPipeIn, tokenfifos);
   mapM(uncurry(mkConnection), zip(fromGearboxes, toMmTokenFifos), clocked_by slowClock, reset_by slowReset);
   Vector#(RowsPerTile, PipeOut#(Vector#(N, MmToken))) fxPipesN = map(toPipeOut, tokenfifos);

   FirstLastPipe#(UInt#(MMSize)) firstLastPipe          <- mkFirstLastPipe();
   Vector#(2, PipeOut#(Tuple2#(Bool,Bool))) firstLastPipes <- mkForkVector(firstLastPipe.pipe);

   for (Integer j = 0; j < rowsPerTile; j = j + 1) begin
      //mkConnection(toGet(aPipes[j]), fxdotprods[j].aInput);
      //mkConnection(toGet(bPipes[j]), fxdotprods[j].bInput);
      (* fire_when_enabled *)
      rule connectA;
	 let x <- toGet(aPipes[j]).get;
	 fxdotprods[j].aInput.put(x);
      endrule
      (* fire_when_enabled *)
      rule connectB;
	 let x <- toGet(bPipes[j]).get;
	 fxdotprods[j].bInput.put(x);
      endrule
   end

`ifdef USE_MIMO_DFIFOS
   for (Integer j = 0; j < rowsPerTile; j = j + 1) begin
      rule dotProdValue;
	 Vector#(K,MmToken) vs;
	 for (Integer k = 0; k < kk; k = k + 1) begin
	    let v <- toGet(fxpipes[j][k]).get();
	    vs[k] = v;
	 end
	 dfifos[j].enq(fromInteger(kk), vs);
      endrule
   end
`endif

   function Bool fifofNotEmpty(FIFOF#(a) fifof); return fifof.notEmpty(); endfunction
   function PipeOut#(Bit#(32)) dotProdMacCount(SharedDotProdServer#(K) dotprodserver); return dotprodserver.debug.macCount; endfunction
   PipeOut#(Bit#(32)) macCountPipe <- mkReducePipes(uncurry(add), map(dotProdMacCount, fxdotprods));

   interface Vector aInputs = zipWith(toCountedPut, aMmTokensPutRegs, map(toPut, aFifos));
   interface Vector bInputs = zipWith(toCountedPut, bMmTokensPutRegs, map(toPut, bFifos));
   interface Vector fxPipes = fxPipesN;
   interface MmTileDebug debug;
      interface PipeOut macCount = macCountPipe;
   endinterface
endmodule : mkMmTile

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

interface DmaMatrixMultiplyDebug;
   method Bit#(32) macCount();
endinterface

// 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 MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import MemUtils::*;
import FloatingPoint::*;
import Pipe::*;
import Arith::*;
import FloatOps::*;
import Timer::*;
import RbmTypes::*;
import Assert::*;
import Connectable::*;
import Clocks::*;
import Gearbox::*;
import XilinxCells::*;
import HostInterface::*;

interface SharedDotProdDebug#(numeric type k);
   interface PipeOut#(Bit#(32)) macCount;
endinterface

interface SharedDotProdServer#(numeric type k);
   interface Put#(MmToken)                 aInput;
   interface Put#(MmToken)                 bInput;
   interface Vector#(k, PipeOut#(MmToken)) pipes;
   interface SharedDotProdDebug#(k) debug;
endinterface

typedef struct {
`ifdef TAGGED_TOKENS
   UInt#(32) row;
   UInt#(32) col;
`endif
   Float v;
   Bool first;
   Bool last;
} MmToken deriving (Eq,Bits);

typedef 8 UB_MulLat; // upper bound on MUL latency?
typedef 8 UB_AddLat; // upper bound on ADD latency?

(* synthesize *)
module  mkSharedInterleavedDotProdServer#(UInt#(TLog#(TMul#(J,K))) label)(SharedDotProdServer#(K))
   provisos(Div#(UB_AddLat,K,gatherSz));

   let ub_MulLat = valueOf(UB_MulLat);
   let ub_AddLat = valueOf(UB_AddLat);
   let kk = valueOf(K);

   Bool verbose = False; //label == 0;

   Reg#(UInt#(20)) countReg     <- mkReg(0);

   FloatAlu mul   <- mkFloatMultiplier(defaultValue);
   FloatAlu adder <- mkFloatAdder(defaultValue);
   FIFOF#(Float) adder_buffer <- mkSizedFIFOF(valueOf(TMul#(K,gatherSz)));

`ifdef TAGGED_TOKENS
   FIFO#(Tuple2#(UInt#(32),UInt#(32))) tag_fifo <- mkSizedFIFO(ub_MulLat);
   Vector#(K,Reg#(Tuple2#(UInt#(32),UInt#(32)))) tag_regs <- replicateM(mkRegU);
`endif

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

   FIFOF#(MmToken)                          afifo   <- mkFIFOF();
   PipeOut#(MmToken)                        aFunnel = toPipeOut(afifo);

   FIFOF#(MmToken)                          bfifo <- mkFIFOF();
   PipeOut#(MmToken)                        bFunnel = toPipeOut(bfifo);

   Reg#(Bit#(16)) firstCnt <- mkReg(0);
   Reg#(Bool)         gReg <- mkReg(False);
   FIFOF#(Float)     gFifo <- mkSizedFIFOF(kk);
   Reg#(Bit#(16))  lastCnt <- mkReg(0);
   Reg#(Bit#(16))gatherCnt <- mkReg(0);

   FIFOF#(Tuple2#(Bool,Bool))    flFifo <- mkSizedFIFOF(ub_MulLat);
   Vector#(K,FIFOF#(MmToken))    dotfifos <- replicateM(mkFIFOF1);
   Reg#(Bit#(TAdd#(1,TLog#(K)))) rowReg <- mkReg(0);

   Reg#(Bit#(32)) lastMul <- mkReg(0);
   Reg#(Bit#(32)) lastAcc <- mkReg(0);
   Reg#(Bit#(32)) lastGather <- mkReg(0);
   Reg#(Bit#(32)) macs <- mkReg(0);

   let gather_phase = lastCnt == fromInteger(kk);

   (* fire_when_enabled *)
   rule connect_adder_buffer;
      match {.acc,.*} <- adder.response.get();
      adder_buffer.enq(acc);
      macs <= macs+1;
   endrule

   (* fire_when_enabled *)
   rule multiply;
      lastMul <= cycles;
      let a <- toGet(aFunnel).get();
      let b <- toGet(bFunnel).get();
      flFifo.enq(tuple2(a.first,a.last));
      if (a.first != b.first)
	 $display("****\n    Warning: a.first=%d != b.first=%d\n****", a.first, b.first);
      if (a.last != b.last)
	 $display("****\n    Warning: a.last=%d != b.last=%d\n****", a.last, b.last);
      if (verbose)
	 $display("%08d multiply: label=%d mulin first=%d last=%d", cycles-lastMul, label, a.first, a.last);
      mul.request.put(tuple2(a.v, b.v));
`ifdef TAGGED_TOKENS
      if(label==0) $display("%d (%d,%d)(%d,%d)", label, a.row, a.col, b.row, b.col);
      tag_fifo.enq(tuple2(a.row,b.col));
`endif
   endrule

   function Action incrementRowReg =
      (action
	  // I have to do this check (instead of relying on wrap-around) because
	  // rowReg has an extra bit to compenseate for bsc's silly Bit#(0) handling
	  if (rowReg+1 == fromInteger(kk)) rowReg <= 0;
	  else rowReg <= rowReg+1;
       endaction);

   (* fire_when_enabled *)
   rule accumulate if (!gather_phase);
      incrementRowReg;
      lastAcc <= cycles;
      match {.first, .last} <- toGet(flFifo).get();
      if (verbose) $display("%08d accumulate: label=%d mulout first=%d last=%d firstCnt=%d lastCnt=%d",
			    cycles-lastAcc, label, first, last, firstCnt, lastCnt);
      match {.resp,.*} <- mul.response.get;
      let acc = unpack(0);
      if (firstCnt == fromInteger(valueOf(TMul#(K,gatherSz))))
	 acc <- toGet(adder_buffer).get;
      else begin
	 firstCnt <= firstCnt+1;
      end
      adder.request.put(tuple2(resp,acc));
      if(last) begin
	 lastCnt <= lastCnt+1;
      end
`ifdef TAGGED_TOKENS
      let row = rowReg;
      let t <- toGet(tag_fifo).get;
      tag_regs[row] <= t;
`endif
   endrule

   (* fire_when_enabled *)
   rule gather if (gather_phase);
      incrementRowReg;
      lastGather <= cycles;
      let row = rowReg;
      let last_row = row == fromInteger(kk-1);
      let last_pass = gatherCnt+1 == fromInteger(valueOf(gatherSz));
      if (verbose)
	 $display("%08d gather: gather=%d row=%d last_pass=%d last_row=%d, gReg=%d",
		  cycles-lastGather, gatherCnt, row, last_pass, last_row, gReg);
      let x <- toGet(adder_buffer).get;
      if (!last_pass) begin
	 if (last_row) begin
	    if (gReg) gatherCnt <= gatherCnt+1;
	    gReg <= !gReg;
	 end
	 if(gReg) begin
	    let y <- toGet(gFifo).get;
	    adder.request.put(tuple2(x,y));
	 end
	 else begin
	    gFifo.enq(x);
	 end
      end
      else begin
`ifdef TAGGED_TOKENS
      	 let row = tpl_1(tag_regs[row]);
      	 let col = tpl_2(tag_regs[row]);
	 dotfifos[row].enq(MmToken{row:row, col:col, v:x});
`else
	 dotfifos[row].enq(MmToken{v:x});
`endif
	 if (last_row) begin
	    gatherCnt <= 0;
	    lastCnt <= 0;
	    firstCnt <= 0;
	 end
      end
   endrule

   Vector#(K,PipeOut#(MmToken)) dotpipes = map(toPipeOut, dotfifos);

   interface Put aInput;
      method Action put(MmToken a);
   	 afifo.enq(a);
	 countReg <= countReg+1;
      endmethod
   endinterface
   interface Put bInput   = toPut(bfifo);
   interface Vector pipes = dotpipes;
   interface SharedDotProdDebug debug;
      interface PipeOut  macCount = toPipeOut(macs._read);
   endinterface
endmodule : mkSharedInterleavedDotProdServer

interface MmTileDebug;
   interface PipeOut#(Bit#(32)) macCount;
endinterface

interface MmTile;
   interface Vector#(RowsPerTile, Put#(MmToken)) aInputs;
   interface Vector#(RowsPerTile, Put#(MmToken)) bInputs;
   interface Vector#(RowsPerTile, PipeOut#(Vector#(N, MmToken))) fxPipes;
   interface MmTileDebug debug;
endinterface

function Put#(a) toCountedPut(Reg#(Bit#(n)) r, Put#(a) p);
   return (interface Put#(a);
      method Action put(a v);
	 r <= r+1;
	 p.put(v);
      endmethod
      endinterface);
endfunction

(* synthesize *)
module  mkMmTile#(Clock slowClock, Reset slowReset, UInt#(TLog#(T)) tile)(MmTile);

   let rowsPerTile = valueOf(RowsPerTile);
   let kk = valueOf(K);

   Vector#(RowsPerTile, Reg#(Bit#(32))) aMmTokensPutRegs <- replicateM(mkReg(0));
   Vector#(RowsPerTile, Reg#(Bit#(32))) bMmTokensPutRegs <- replicateM(mkReg(0));
   Vector#(RowsPerTile, Reg#(Bit#(32))) aMmTokensReadRegs <- replicateM(mkReg(0));
   Vector#(RowsPerTile, Reg#(Bit#(32))) bMmTokensReadRegs <- replicateM(mkReg(0));

   Vector#(RowsPerTile, FIFOF#(MmToken))   aFifos <- replicateM(mkFIFOF);
   Vector#(RowsPerTile, PipeOut#(MmToken)) aPipes = zipWith(toCountedPipeOut, aMmTokensReadRegs, map(toPipeOut, aFifos));
   Vector#(RowsPerTile,  FIFOF#(MmToken))   bFifos <- replicateM(mkFIFOF);
   Vector#(RowsPerTile,  PipeOut#(MmToken)) bPipes = zipWith(toCountedPipeOut, bMmTokensReadRegs, map(toPipeOut, bFifos));

   function Vector#(k,PipeOut#(MmToken)) getDotProdServerPipes(SharedDotProdServer#(k) s); return s.pipes; endfunction
   Vector#(RowsPerTile, SharedDotProdServer#(K)) fxdotprods <- mapM(mkSharedInterleavedDotProdServer, map(fromInteger,genVector));
   Vector#(RowsPerTile, Vector#(K, PipeOut#(MmToken))) fxpipes = map(getDotProdServerPipes, fxdotprods);
//`define USE_MIMO_DFIFOS // this version is faster
   let fastClock <- exposeCurrentClock();
   let fastReset <- exposeCurrentReset();
`ifndef USE_MIMO_DFIFOS
   Vector#(RowsPerTile, PipeOut#(Vector#(K, MmToken))) fxPipesK <- mapM(mkJoinVector(id), fxpipes);
   Vector#(RowsPerTile, PipeOut#(MmToken)) fxPipes1MmToken <- mapM(mkFunnel1, fxPipesK);
   Vector#(RowsPerTile, PipeOut#(Vector#(1, MmToken))) fxPipes1 = map(mapPipe(replicate), fxPipes1MmToken);
`else
   MIMOConfiguration mimoCfg = defaultValue;
   Vector#(RowsPerTile, MIMO#(K,1,TAdd#(K,1),MmToken)) dfifos <- replicateM(mkMIMO(mimoCfg));
   Vector#(RowsPerTile, PipeOut#(Vector#(1, MmToken))) fxPipes1 = map(toPipeOut, dfifos);
`endif
   Vector#(RowsPerTile, Gearbox#(1, N, MmToken)) gearboxes <- replicateM(mk1toNGearbox(fastClock, fastReset, slowClock, slowReset));
   Vector#(RowsPerTile, PipeIn#(Vector#(1,MmToken))) toGearboxes = map(toPipeIn, gearboxes);
   Vector#(RowsPerTile, PipeOut#(Vector#(N, MmToken))) fromGearboxes = map(toPipeOut, gearboxes);
   mapM(uncurry(mkConnection), zip(fxPipes1, toGearboxes));
   // introduce a buffer to help vivado meet timing on vc707
   Vector#(RowsPerTile, FIFOF#(Vector#(N,MmToken)))    tokenfifos <- replicateM(mkFIFOF(clocked_by slowClock, reset_by slowReset));
   Vector#(RowsPerTile, PipeIn#(Vector#(N,MmToken))) toMmTokenFifos = map(toPipeIn, tokenfifos);
   mapM(uncurry(mkConnection), zip(fromGearboxes, toMmTokenFifos), clocked_by slowClock, reset_by slowReset);
   Vector#(RowsPerTile, PipeOut#(Vector#(N, MmToken))) fxPipesN = map(toPipeOut, tokenfifos);

   FirstLastPipe#(UInt#(MMSize)) firstLastPipe          <- mkFirstLastPipe();
   Vector#(2, PipeOut#(Tuple2#(Bool,Bool))) firstLastPipes <- mkForkVector(firstLastPipe.pipe);

   for (Integer j = 0; j < rowsPerTile; j = j + 1) begin
      //mkConnection(toGet(aPipes[j]), fxdotprods[j].aInput);
      //mkConnection(toGet(bPipes[j]), fxdotprods[j].bInput);
      (* fire_when_enabled *)
      rule connectA;
	 let x <- toGet(aPipes[j]).get;
	 fxdotprods[j].aInput.put(x);
      endrule
      (* fire_when_enabled *)
      rule connectB;
	 let x <- toGet(bPipes[j]).get;
	 fxdotprods[j].bInput.put(x);
      endrule
   end

`ifdef USE_MIMO_DFIFOS
   for (Integer j = 0; j < rowsPerTile; j = j + 1) begin
      rule dotProdValue;
	 Vector#(K,MmToken) vs;
	 for (Integer k = 0; k < kk; k = k + 1) begin
	    let v <- toGet(fxpipes[j][k]).get();
	    vs[k] = v;
	 end
	 dfifos[j].enq(fromInteger(kk), vs);
      endrule
   end
`endif

   function Bool fifofNotEmpty(FIFOF#(a) fifof); return fifof.notEmpty(); endfunction
   function PipeOut#(Bit#(32)) dotProdMacCount(SharedDotProdServer#(K) dotprodserver); return dotprodserver.debug.macCount; endfunction
   PipeOut#(Bit#(32)) macCountPipe <- mkReducePipes(uncurry(add), map(dotProdMacCount, fxdotprods));

   interface Vector aInputs = zipWith(toCountedPut, aMmTokensPutRegs, map(toPut, aFifos));
   interface Vector bInputs = zipWith(toCountedPut, bMmTokensPutRegs, map(toPut, bFifos));
   interface Vector fxPipes = fxPipesN;
   interface MmTileDebug debug;
      interface PipeOut macCount = macCountPipe;
   endinterface
endmodule : mkMmTile

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

interface DmaMatrixMultiplyDebug;
   method Bit#(32) macCount();
endinterface


went back to mkMMCMHACK().

went back to mkMMCMHACK().

// bsv libraries
import Vector::*;
import FIFO::*;
import Connectable::*;
import DefaultValue::*;

// portz libraries
import Portal::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import Dma::*;

// generated by tool
import ImageCaptureIndicationProxy::*;
import ImageCaptureRequestWrapper::*;
import ImageonSerdesIndicationProxy::*;
import HdmiInternalIndicationProxy::*;
//import ImageCaptureRequestInternal::*;
import ImageonSerdesRequestWrapper::*;
import HdmiInternalRequestWrapper::*;
import ImageonSensorRequestWrapper::*;
import ImageCaptureRequestWrapper::*;

// defined by user
import FrequencyCounter::*;
import ImageCapture::*;
import GetPut::*;
import Connectable :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;
import XbsvSpi :: *;

import GetPutWithClocks :: *;
import Imageon::*;
import IserdesDatadeser::*;
import HDMI::*;
import SensorToVideo::*;
import XilinxCells::*;
import XbsvXilinxCells::*;
import YUV::*;
import PS7LIB :: *;
import Imageon :: *;

typedef enum { ImageCapture, ImageonSerdesRequest, HdmiInternalRequest, ImageonSensorRequest,
    ImageCaptureIndication, ImageonSerdesIndication, HdmiInternalIndication} IfcNames deriving (Eq,Bits);

interface ImageCapturePins;
   interface SpiPins spi;
   interface ImageonSensorPins pins;
   //interface ImageonTopPins toppins;
   interface ImageonSerdesPins serpins;
   interface HDMI hdmi;
   //method Bit#(1) i2c_mux_reset_n();
endinterface

module mkPortalTop#(Clock clock200, Clock fmc_imageon_clk1)(PortalTop#(addrWidth,64,ImageCapturePins));
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   // instantiate user portals
   ImageCaptureIndicationProxy captureIndicationProxy <- mkImageCaptureIndicationProxy(ImageCaptureIndication);
   ImageonSerdesIndicationProxy serdesIndicationProxy <- mkImageonSerdesIndicationProxy(ImageonSerdesIndication);
   HdmiInternalIndicationProxy hdmiIndicationProxy <- mkHdmiInternalIndicationProxy(HdmiInternalIndication);

   //ImageCaptureRequest captureRequestInternal <- mkImageCaptureRequest(captureIndicationProxy.ifc);

//////
   Clock clock200_buf <- mkClockBUFG(clocked_by clock200);
   IDELAYCTRL idel <- mkIDELAYCTRL(2, clocked_by clock200_buf);
/*
   ClockGenerator7AdvParams clockParams = defaultValue;
   clockParams.bandwidth          = "OPTIMIZED";
   clockParams.compensation       = "ZHOLD";
   clockParams.clkfbout_mult_f    = 8.000;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkin1_period      = 6.734007; // 148.5 MHz
   clockParams.clkin2_period      = 6.734007;
   clockParams.clkout0_divide_f   = 8.000;    // 148.5 MHz
   clockParams.clkout0_duty_cycle = 0.5;
   clockParams.clkout0_phase      = 0.0000;
   clockParams.clkout1_divide     = 32;       // 37.125 MHz
   clockParams.clkout1_duty_cycle = 0.5;
   clockParams.clkout1_phase      = 0.0000;
   clockParams.divclk_divide      = 1;
   clockParams.ref_jitter1        = 0.010;
   clockParams.ref_jitter2        = 0.010;

   ClockGenerator7 clockGen <- mkClockGenerator7Adv(clockParams, clocked_by fmc_imageon_clk1);
   Clock hdmi_clock = clockGen.clkout0;    // 148.5   MHz
   Clock imageon_clock = clockGen.clkout1; //  37.125 MHz
*/
    MMCMHACK mmcmhack <- mkMMCMHACK(clocked_by fmc_imageon_clk1);
    Clock hdmi_clock <- mkClockBUFG(clocked_by mmcmhack.mmcmadv.clkout0);
    Clock imageon_clock <- mkClockBUFG(clocked_by mmcmhack.mmcmadv.clkout1);
    C2B fblink <- mkC2B(mmcmhack.mmcmadv.clkfbout, clocked_by fmc_imageon_clk1);
    rule foorule;
    mmcmhack.mmcmadv.clkfbin(fblink.o());
    //let foo = fblink.o();
    //mmcmhack.mmcmadv.clkfbin(foo);
    endrule

    Reset fmc_imageon_reset <- mkAsyncReset(2, defaultReset, fmc_imageon_clk1);
    Reset hdmi_reset <- mkAsyncReset(2, defaultReset, hdmi_clock);
    Reset imageon_reset <- mkAsyncReset(2, defaultReset, imageon_clock);
    SyncPulseIfc vsyncPulse <- mkSyncHandshake(hdmi_clock, hdmi_reset, imageon_clock);

    ISerdes serdes <- mkISerdes(defaultClock, defaultReset, serdesIndicationProxy.ifc,
				clocked_by imageon_clock, reset_by imageon_reset);
    SPI#(Bit#(26)) spiController <- mkSPI(1000);
    SensorToVideo converter <- mkSensorToVideo(clocked_by hdmi_clock, reset_by hdmi_reset);
    HdmiGenerator hdmiGen <- mkHdmiGenerator(defaultClock, defaultReset,
        vsyncPulse, hdmiIndicationProxy.ifc, clocked_by hdmi_clock, reset_by hdmi_reset);
    ImageonSensor fromSensor <- mkImageonSensor(defaultClock, defaultReset, serdes.data, vsyncPulse.pulse(),
        hdmiGen.control, hdmi_clock, hdmi_reset, clocked_by imageon_clock, reset_by imageon_reset);

    rule spiControllerResponse;
        Bit#(26) v <- spiController.response.get();
       captureIndicationProxy.ifc.spi_response(extend(v));
    endrule

   Reg#(Bit#(1)) i2c_mux_reset_n_reg <- mkReg(0);
   FrequencyCounter axiFreqCounter <- mkFrequencyCounter(defaultClock, defaultReset);
   FrequencyCounter hdmiFreqCounter <- mkFrequencyCounter(hdmi_clock, hdmi_reset);
   FrequencyCounter imageonFreqCounter <- mkFrequencyCounter(imageon_clock, imageon_reset);
   FrequencyCounter fmcFreqCounter <- mkFrequencyCounter(fmc_imageon_clk1, fmc_imageon_reset);

   rule gotAxiClockPeriod;
      let cycles <- axiFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.axi_clock_period(cycles);
   endrule
   rule gotHdmiClockPeriod;
      let cycles <- hdmiFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.hdmi_clock_period(cycles);
   endrule
   rule gotImageonClockPeriod;
      let cycles <- imageonFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.imageon_clock_period(cycles);
   endrule
   rule gotFmcClockPeriod;
      let cycles <- fmcFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.fmc_clock_period(cycles);
   endrule

   ImageCaptureRequest imageCaptureRequest = (interface ImageCaptureRequest;
      method Action get_debugind();
         captureIndicationProxy.ifc.debugind(fromSensor.control.get_debugind());
      endmethod
      method Action put_spi_request(Bit#(32) v);
         spiController.request.put(truncate(v));
      endmethod
      method Action set_i2c_mux_reset_n(Bit#(1) v);
	 i2c_mux_reset_n_reg <= v;
      endmethod
      method Action measure_axi_clock_period(Bit#(32) cycles_100mhz);
	 axiFreqCounter.start(cycles_100mhz);
      endmethod
      method Action measure_hdmi_clock_period(Bit#(32) cycles_100mhz);
         hdmiFreqCounter.start(cycles_100mhz);
      endmethod
      method Action measure_imageon_clock_period(Bit#(32) cycles_100mhz);
         imageonFreqCounter.start(cycles_100mhz);
      endmethod
      method Action measure_fmc_clock_period(Bit#(32) cycles_100mhz);
         fmcFreqCounter.start(cycles_100mhz);
      endmethod
      endinterface);

    ImageCaptureRequestWrapper captureRequestWrapper <- mkImageCaptureRequestWrapper(ImageCapture, imageCaptureRequest);
    ImageonSerdesRequestWrapper serdesRequestWrapper <- mkImageonSerdesRequestWrapper(ImageonSerdesRequest,serdes.control);
    HdmiInternalRequestWrapper hdmiRequestWrapper <- mkHdmiInternalRequestWrapper(HdmiInternalRequest,hdmiGen.control);
    ImageonSensorRequestWrapper sensorRequestWrapper <- mkImageonSensorRequestWrapper(ImageonSensorRequest,fromSensor.control);

    rule xsviConnection;
        let xsvi <- fromSensor.get_data();
        //bsi.dataIn(extend(pack(xsvi)), extend(pack(xsvi)));
        //converter.in.put(xsvi);
        //let xvideo <- converter.out.get();
        //hdmiGen.rgb(xvideo);
        Bit#(64) pixel = {40'b0, xsvi[9:2], xsvi[9:2], xsvi[9:2]};
        hdmiGen.request.put(pixel);
    endrule

   Vector#(7,StdPortal) portals;
   portals[0] = captureRequestWrapper.portalIfc;
   portals[1] = captureIndicationProxy.portalIfc;
   portals[2] = serdesRequestWrapper.portalIfc;
   portals[3] = serdesIndicationProxy.portalIfc;
   portals[4] = hdmiRequestWrapper.portalIfc;
   portals[5] = hdmiIndicationProxy.portalIfc;
   portals[6] = sensorRequestWrapper.portalIfc;

   // instantiate system directory
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface master = null_mem_master;
   //interface leds = captureRequestInternal.leds;

   interface ImageCapturePins pins;
       interface SpiPins spi = spiController.pins;
       interface ImageonSensorPins pins = fromSensor.pins;
       interface ImageonSerdesPins serpins = serdes.pins;
       interface HDMI hdmi = hdmiGen.hdmi;
       //method Bit#(1) i2c_mux_reset_n(); return i2c_mux_reset_n_reg; endmethod
   endinterface

endmodule : mkPortalTop

// bsv libraries
import Vector::*;
import FIFO::*;
import Connectable::*;
import DefaultValue::*;

// portz libraries
import Portal::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import Dma::*;

// generated by tool
import ImageCaptureIndicationProxy::*;
import ImageCaptureRequestWrapper::*;
import ImageonSerdesIndicationProxy::*;
import HdmiInternalIndicationProxy::*;
//import ImageCaptureRequestInternal::*;
import ImageonSerdesRequestWrapper::*;
import HdmiInternalRequestWrapper::*;
import ImageonSensorRequestWrapper::*;
import ImageCaptureRequestWrapper::*;

// defined by user
import FrequencyCounter::*;
import ImageCapture::*;
import GetPut::*;
import Connectable :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;
import XbsvSpi :: *;

import GetPutWithClocks :: *;
import Imageon::*;
import IserdesDatadeser::*;
import HDMI::*;
import SensorToVideo::*;
import XilinxCells::*;
import XbsvXilinxCells::*;
import YUV::*;
import PS7LIB :: *;
import Imageon :: *;

typedef enum { ImageCapture, ImageonSerdesRequest, HdmiInternalRequest, ImageonSensorRequest,
    ImageCaptureIndication, ImageonSerdesIndication, HdmiInternalIndication} IfcNames deriving (Eq,Bits);

interface ImageCapturePins;
   interface SpiPins spi;
   interface ImageonSensorPins pins;
   //interface ImageonTopPins toppins;
   interface ImageonSerdesPins serpins;
   interface HDMI hdmi;
   method Bit#(1) i2c_mux_reset_n();
endinterface

module mkPortalTop#(Clock clock200, Clock fmc_imageon_clk1)(PortalTop#(addrWidth,64,ImageCapturePins));
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   // instantiate user portals
   ImageCaptureIndicationProxy captureIndicationProxy <- mkImageCaptureIndicationProxy(ImageCaptureIndication);
   ImageonSerdesIndicationProxy serdesIndicationProxy <- mkImageonSerdesIndicationProxy(ImageonSerdesIndication);
   HdmiInternalIndicationProxy hdmiIndicationProxy <- mkHdmiInternalIndicationProxy(HdmiInternalIndication);

   //ImageCaptureRequest captureRequestInternal <- mkImageCaptureRequest(captureIndicationProxy.ifc);

//////
   Clock clock200_buf <- mkClockBUFG(clocked_by clock200);
   IDELAYCTRL idel <- mkIDELAYCTRL(2, clocked_by clock200_buf);

   ClockGenerator7AdvParams clockParams = defaultValue;
   clockParams.bandwidth          = "OPTIMIZED";
   clockParams.compensation       = "ZHOLD";
   clockParams.clkfbout_mult_f    = 8.000;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkin1_period      = 6.734007; // 148.5 MHz
   clockParams.clkin2_period      = 6.734007;
   clockParams.clkout0_divide_f   = 8.000;    // 148.5 MHz
   clockParams.clkout0_duty_cycle = 0.5;
   clockParams.clkout0_phase      = 0.0000;
   clockParams.clkout1_divide     = 32;       // 37.125 MHz
   clockParams.clkout1_duty_cycle = 0.5;
   clockParams.clkout1_phase      = 0.0000;
   clockParams.divclk_divide      = 1;
   clockParams.ref_jitter1        = 0.010;
   clockParams.ref_jitter2        = 0.010;

   ClockGenerator7 clockGen <- mkClockGenerator7Adv(clockParams, clocked_by fmc_imageon_clk1);
   Clock hdmi_clock = clockGen.clkout0;    // 148.5   MHz
   Clock imageon_clock = clockGen.clkout1; //  37.125 MHz

    Reset fmc_imageon_reset <- mkAsyncReset(2, defaultReset, fmc_imageon_clk1);
    Reset hdmi_reset <- mkAsyncReset(2, defaultReset, hdmi_clock);
    Reset imageon_reset <- mkAsyncReset(2, defaultReset, imageon_clock);
    SyncPulseIfc vsyncPulse <- mkSyncHandshake(hdmi_clock, hdmi_reset, imageon_clock);

    ISerdes serdes <- mkISerdes(defaultClock, defaultReset, serdesIndicationProxy.ifc,
				clocked_by imageon_clock, reset_by imageon_reset);
    SPI#(Bit#(26)) spiController <- mkSPI(1000);
    SensorToVideo converter <- mkSensorToVideo(clocked_by hdmi_clock, reset_by hdmi_reset);
    HdmiGenerator hdmiGen <- mkHdmiGenerator(defaultClock, defaultReset,
        vsyncPulse, hdmiIndicationProxy.ifc, clocked_by hdmi_clock, reset_by hdmi_reset);
    ImageonSensor fromSensor <- mkImageonSensor(defaultClock, defaultReset, serdes.data, vsyncPulse.pulse(),
        hdmiGen.control, hdmi_clock, hdmi_reset, clocked_by imageon_clock, reset_by imageon_reset);

    rule spiControllerResponse;
        Bit#(26) v <- spiController.response.get();
       captureIndicationProxy.ifc.spi_response(extend(v));
    endrule

   Reg#(Bit#(1)) i2c_mux_reset_n_reg <- mkReg(0);
   FrequencyCounter axiFreqCounter <- mkFrequencyCounter(defaultClock, defaultReset);
   FrequencyCounter hdmiFreqCounter <- mkFrequencyCounter(hdmi_clock, hdmi_reset);
   FrequencyCounter imageonFreqCounter <- mkFrequencyCounter(imageon_clock, imageon_reset);
   FrequencyCounter fmcFreqCounter <- mkFrequencyCounter(fmc_imageon_clk1, fmc_imageon_reset);

   rule gotAxiClockPeriod;
      let cycles <- axiFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.axi_clock_period(cycles);
   endrule
   rule gotHdmiClockPeriod;
      let cycles <- hdmiFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.hdmi_clock_period(cycles);
   endrule
   rule gotImageonClockPeriod;
      let cycles <- imageonFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.imageon_clock_period(cycles);
   endrule
   rule gotFmcClockPeriod;
      let cycles <- fmcFreqCounter.elapsedCycles();
      captureIndicationProxy.ifc.fmc_clock_period(cycles);
   endrule

   ImageCaptureRequest imageCaptureRequest = (interface ImageCaptureRequest;
      method Action get_debugind();
         captureIndicationProxy.ifc.debugind(fromSensor.control.get_debugind());
      endmethod
      method Action put_spi_request(Bit#(32) v);
         spiController.request.put(truncate(v));
      endmethod
      method Action set_i2c_mux_reset_n(Bit#(1) v);
	 i2c_mux_reset_n_reg <= v;
      endmethod
      method Action measure_axi_clock_period(Bit#(32) cycles_100mhz);
	 axiFreqCounter.start(cycles_100mhz);
      endmethod
      method Action measure_hdmi_clock_period(Bit#(32) cycles_100mhz);
         hdmiFreqCounter.start(cycles_100mhz);
      endmethod
      method Action measure_imageon_clock_period(Bit#(32) cycles_100mhz);
         imageonFreqCounter.start(cycles_100mhz);
      endmethod
      method Action measure_fmc_clock_period(Bit#(32) cycles_100mhz);
         fmcFreqCounter.start(cycles_100mhz);
      endmethod
      endinterface);

    ImageCaptureRequestWrapper captureRequestWrapper <- mkImageCaptureRequestWrapper(ImageCapture, imageCaptureRequest);
    ImageonSerdesRequestWrapper serdesRequestWrapper <- mkImageonSerdesRequestWrapper(ImageonSerdesRequest,serdes.control);
    HdmiInternalRequestWrapper hdmiRequestWrapper <- mkHdmiInternalRequestWrapper(HdmiInternalRequest,hdmiGen.control);
    ImageonSensorRequestWrapper sensorRequestWrapper <- mkImageonSensorRequestWrapper(ImageonSensorRequest,fromSensor.control);

    rule xsviConnection;
        let xsvi <- fromSensor.get_data();
        //bsi.dataIn(extend(pack(xsvi)), extend(pack(xsvi)));
        //converter.in.put(xsvi);
        //let xvideo <- converter.out.get();
        //hdmiGen.rgb(xvideo);
        Bit#(64) pixel = {40'b0, xsvi[9:2], xsvi[9:2], xsvi[9:2]};
        hdmiGen.request.put(pixel);
    endrule

   Vector#(7,StdPortal) portals;
   portals[0] = captureRequestWrapper.portalIfc;
   portals[1] = captureIndicationProxy.portalIfc;
   portals[2] = serdesRequestWrapper.portalIfc;
   portals[3] = serdesIndicationProxy.portalIfc;
   portals[4] = hdmiRequestWrapper.portalIfc;
   portals[5] = hdmiIndicationProxy.portalIfc;
   portals[6] = sensorRequestWrapper.portalIfc;

   // instantiate system directory
   StdDirectory dir <- mkStdDirectory(portals);
   let ctrl_mux <- mkSlaveMux(dir,portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface master = null_mem_master;
   //interface leds = captureRequestInternal.leds;

   interface ImageCapturePins pins;
       interface SpiPins spi = spiController.pins;
       interface ImageonSensorPins pins = fromSensor.pins;
       interface ImageonSerdesPins serpins = serdes.pins;
       interface HDMI hdmi = hdmiGen.hdmi;
       method Bit#(1) i2c_mux_reset_n(); return i2c_mux_reset_n_reg; endmethod
   endinterface

endmodule : mkPortalTop


cleanup

cleanup

import Clocks::*;
import Vector::*;

import ConnectalClocks::*;
import LedController::*;
import PushButtonController::*;

import AlteraExtra::*;
import ALTERA_SI570_WRAPPER::*;

(* always_ready, always_enabled *)
interface DE5Pins;
`ifndef SIMULATION
   method Action osc_50(Bit#(1) b3d, Bit#(1) b4a, Bit#(1) b4d, Bit#(1) b7a, Bit#(1) b7d, Bit#(1) b8a, Bit#(1) b8d);
   method Action sfp(Bit#(1) refclk);
   method Vector#(4, Bit#(1)) serial_tx_data;
   method Action serial_rx(Vector#(4, Bit#(1)) data);
   method Bit#(4) led;
   method Bit#(4) led_bracket;
   method Action buttons(Vector#(4, Bit#(1)) v);
   interface Si570wrapI2c i2c;
   interface De5SfpCtrl#(4) sfpctrl;
   interface Clock deleteme_unused_clock;
   interface Clock deleteme_unused_clock2;
   interface Clock deleteme_unused_clock3;
   interface Reset deleteme_unused_reset;
`endif
endinterface

interface De5Clocks;
   interface Si570wrapI2c i2c;
   interface Clock clock_50;
   interface Reset reset_50_n;
   interface Clock clock_156_25;
   interface Reset reset_156_25_n;
   interface Clock clock_644_53;
endinterface

module mkDe5Clocks#(Bit#(1) clk_50, Bit#(1) clk_644)(De5Clocks);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   B2C1 iclock_50 <- mkB2C1();
   B2C1 iclock_644 <- mkB2C1();

   //Reset reset_50 <- mkResetInverter(reset_n, clocked_by clk_50_b4a_buf.outclk);
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, iclock_50.c);
   Reset reset_644 <- mkResetInverter(defaultReset, clocked_by iclock_644.c);
   //Reset reset_644_53_n <- mkAsyncReset(2, reset_n, sfp_refclk);

   // ===================================
   // PLL:
   // Input:   SFP REFCLK from SI570
   // Output:  156.25MHz
   // Reset: Active High, must invert default Reset
   PLL156 pll156 <- mkPLL156(iclock_644.c, reset_644, clocked_by iclock_644.c, reset_by reset_644);
   Clock clk_156_25 = pll156.outclk_0;
   Reset rst_156   <- mkResetInverter(defaultReset, clocked_by clk_156_25);
   Reset rst_156_n <- mkAsyncReset(2, defaultReset, clk_156_25, clocked_by clk_156_25);

   // ===================================
   // PLL: SI570 configurable clock
   // Input:
   // Output:
   // Reset: Active Low, use default Reset
   Si570Wrap si570 <- mkSi570Wrap(iclock_50.c, rst_50_n, clocked_by iclock_50.c, reset_by rst_50_n);

   rule si570_connections;
      let ifreq_mode = 3'b110;  //644.53125 MHZ
      si570.ifreq.mode(ifreq_mode);
      si570.istart.go(1'b0);
   endrule

   rule input_clock_50;
      iclock_50.inputclock(clk_50);
   endrule

   rule input_clock_644;
      iclock_644.inputclock(clk_644);
   endrule

   interface i2c = si570.i2c;
   interface clock_50 = iclock_50.c;
   interface reset_50_n = rst_50_n;
   interface clock_156_25 = clk_156_25;
   interface reset_156_25_n = rst_156_n;
   interface clock_644_53 = iclock_644.c;
endmodule

interface De5Leds;
   method Bit#(4) led_out;
endinterface

module mkDe5Leds#(Clock clk0, Clock clk1, Clock clk2, Clock clk3)(De5Leds);
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;

   Reset reset0 <- mkSyncReset(2, defaultReset, clk0);
   Reset reset1 <- mkSyncReset(2, defaultReset, clk1);
   Reset reset2 <- mkSyncReset(2, defaultReset, clk2);
   Reset reset3 <- mkSyncReset(2, defaultReset, clk3);

   LedController led0 <- mkLedController(False, clocked_by clk0, reset_by reset0);
   LedController led1 <- mkLedController(False, clocked_by clk1, reset_by reset1);
   LedController led2 <- mkLedController(False, clocked_by clk2, reset_by reset2);
   LedController led3 <- mkLedController(False, clocked_by clk3, reset_by reset3);

   rule led0_run;
      led0.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   rule led1_run;
      led1.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   rule led2_run;
      led2.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   rule led3_run;
      led3.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   method led_out = {led0.ifc.out,
                     led1.ifc.out,
                     led2.ifc.out,
                     led3.ifc.out
                     };
endmodule

interface De5SfpCtrl#(numeric type nPorts);
   method Action los (Vector#(nPorts, Bit#(1)) v);
   method Action mod0_presnt_n (Vector#(nPorts, Bit#(1)) v);
   method Action txfault (Vector#(nPorts, Bit#(1)) v);
// SCL/SDA not implemented
(* prefix="", result="ratesel0" *)   method Vector#(nPorts, Bit#(1)) ratesel0;
(* prefix="", result="ratesel1" *)   method Vector#(nPorts, Bit#(1)) ratesel1;
(* prefix="", result="txdisable" *)   method Vector#(nPorts, Bit#(1)) txdisable;
endinterface

module mkDe5SfpCtrl(De5SfpCtrl#(nPorts));
   Vector#(nPorts, Wire#(Bit#(1))) los_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) mod0_presnt_n_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) txfault_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) ratesel0_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) ratesel1_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) txdisable_wire <- replicateM(mkDWire(0));

   for (Integer i=0; i<valueOf(nPorts); i=i+1) begin
      rule set_output;
         ratesel0_wire[i] <= 1'b1;
         ratesel1_wire[i] <= 1'b1;
         txdisable_wire[i] <= 1'b0;
      endrule
   end

   method los = writeVReg(los_wire);
   method mod0_presnt_n = writeVReg(mod0_presnt_n_wire);
   method txfault = writeVReg(txfault_wire);
   method ratesel0 = readVReg(ratesel0_wire);
   method ratesel1 = readVReg(ratesel1_wire);
   method txdisable = readVReg(txdisable_wire);
endmodule

interface De5Buttons#(numeric type nButtons);
   method Action pins(Vector#(nButtons, Bit#(1)) v);
(* prefix="", result="pressed" *)   method Vector#(nButtons, Bool) pressed;
endinterface

module mkDe5Buttons(De5Buttons#(nButtons));
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;
   Vector#(nButtons, Wire#(Bit#(1))) button_in <- replicateM(mkDWire(0));
   Vector#(nButtons, Wire#(Bool)) button_pressed <- replicateM(mkDWire(False));

   Vector#(4, PushButtonController) buttons <- replicateM(mkPushButtonController(defaultClock));
   for (Integer i=0; i<valueOf(nButtons); i=i+1) begin
      rule setPushButtonInput;
         buttons[i].ifc.button(button_in[i]);
      endrule

      rule setPushButtonParam;
         buttons[i].setRepeatParams(10, 10);
      endrule

      rule setPushButtonOutput;
         button_pressed[i] <= buttons[i].pressed;
      endrule
   end

   method pins = writeVReg(button_in);
   method pressed = readVReg(button_pressed);
endmodule

import Clocks::*;
import Vector::*;

import ConnectalClocks::*;
import LedController::*;
import PushButtonController::*;

import AlteraExtra::*;
import ALTERA_SI570_WRAPPER::*;

(* always_ready, always_enabled *)
interface DE5Pins;
`ifndef SIMULATION
   method Action osc_50(Bit#(1) b3d, Bit#(1) b4a, Bit#(1) b4d, Bit#(1) b7a, Bit#(1) b7d, Bit#(1) b8a, Bit#(1) b8d);
   method Action sfp(Bit#(1) refclk);
   method Vector#(4, Bit#(1)) serial_tx_data;
   method Action serial_rx(Vector#(4, Bit#(1)) data);
   method Bit#(4) led;
   method Bit#(4) led_bracket;
   method Action buttons(Vector#(4, Bit#(1)) v);
   interface Si570wrapI2c i2c;
   interface De5SfpCtrl#(4) sfpctrl;
   interface Clock deleteme_unused_clock;
   interface Clock deleteme_unused_clock2;
   interface Clock deleteme_unused_clock3;
   interface Reset deleteme_unused_reset;
`endif
endinterface

interface De5Clocks;
   interface Si570wrapI2c i2c;
   interface Clock clock_50;
   interface Reset reset_50_n;
   interface Clock clock_156_25;
   interface Reset reset_156_25_n;
   interface Clock clock_644_53;
endinterface

module mkDe5Clocks#(Bit#(1) clk_50, Bit#(1) clk_644)(De5Clocks);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   B2C1 iclock_50 <- mkB2C1();
   B2C1 iclock_644 <- mkB2C1();

   //Reset reset_50 <- mkResetInverter(reset_n, clocked_by clk_50_b4a_buf.outclk);
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, iclock_50.c);
   Reset reset_644 <- mkResetInverter(defaultReset, clocked_by iclock_644.c);
   //Reset reset_644_53_n <- mkAsyncReset(2, reset_n, sfp_refclk);

   // ===================================
   // PLL:
   // Input:   SFP REFCLK from SI570
   // Output:  156.25MHz
   // Reset: Active High, must invert default Reset
   PLL156 pll156 <- mkPLL156(iclock_644.c, reset_644, clocked_by iclock_644.c, reset_by reset_644);
   Clock clk_156_25 = pll156.outclk_0;
   Reset rst_156   <- mkResetInverter(defaultReset, clocked_by clk_156_25);
   Reset rst_156_n <- mkAsyncReset(2, defaultReset, clk_156_25, clocked_by clk_156_25);

   // ===================================
   // PLL: SI570 configurable clock
   // Input:
   // Output:
   // Reset: Active Low, use default Reset
   Si570Wrap si570 <- mkSi570Wrap(iclock_50.c, rst_50_n, clocked_by iclock_50.c, reset_by rst_50_n);

   rule si570_connections;
      let ifreq_mode = 3'b110;  //644.53125 MHZ
      si570.ifreq.mode(ifreq_mode);
      si570.istart.go(1'b0);
   endrule

   rule input_clock_50;
      iclock_50.inputclock(clk_50);
   endrule

   rule input_clock_644;
      iclock_644.inputclock(clk_644);
   endrule

   interface i2c = si570.i2c;
   interface clock_50 = iclock_50.c;
   interface reset_50_n = rst_50_n;
   interface clock_156_25 = clk_156_25;
   interface reset_156_25_n = rst_156_n;
   interface clock_644_53 = iclock_644.c;
endmodule

interface De5Leds;
   method Bit#(4) led_out;
endinterface

module mkDe5Leds#(Clock clk0, Clock clk1, Clock clk2, Clock clk3)(De5Leds);
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;

   Reset reset0 <- mkSyncReset(2, defaultReset, clk0);
   Reset reset1 <- mkSyncReset(2, defaultReset, clk1);
   Reset reset2 <- mkSyncReset(2, defaultReset, clk2);
   Reset reset3 <- mkSyncReset(2, defaultReset, clk3);

   LedController led0 <- mkLedController(False, clocked_by clk0, reset_by reset0);
   LedController led1 <- mkLedController(False, clocked_by clk1, reset_by reset1);
   LedController led2 <- mkLedController(False, clocked_by clk2, reset_by reset2);
   LedController led3 <- mkLedController(False, clocked_by clk3, reset_by reset3);

   rule led0_run;
      led0.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   rule led1_run;
      led1.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   rule led2_run;
      led2.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   rule led3_run;
      led3.setPeriod(led_off, 500, led_on_max, 500);
   endrule

   method led_out = {led0.ifc.out,
                     led1.ifc.out,
                     led2.ifc.out,
                     led3.ifc.out
                     };
endmodule

interface De5SfpCtrl#(numeric type nPorts);
   method Action los (Vector#(nPorts, Bit#(1)) v);
   method Action mod0_presnt_n (Vector#(nPorts, Bit#(1)) v);
   method Action txfault (Vector#(nPorts, Bit#(1)) v);
// SCL/SDA not implemented
(* prefix="", result="ratesel0" *)   method Vector#(nPorts, Bit#(1)) ratesel0;
(* prefix="", result="ratesel1" *)   method Vector#(nPorts, Bit#(1)) ratesel1;
(* prefix="", result="txdisable" *)   method Vector#(nPorts, Bit#(1)) txdisable;
endinterface

module mkDe5SfpCtrl(De5SfpCtrl#(nPorts));
   Vector#(nPorts, Wire#(Bit#(1))) los_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) mod0_presnt_n_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) txfault_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) ratesel0_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) ratesel1_wire <- replicateM(mkDWire(0));
   Vector#(nPorts, Wire#(Bit#(1))) txdisable_wire <- replicateM(mkDWire(0));

   for (Integer i=0; i<valueOf(nPorts); i=i+1) begin
      rule set_output;
         ratesel0_wire[i] <= 1'b1;
         ratesel1_wire[i] <= 1'b1;
         txdisable_wire[i] <= 1'b0;
      endrule
   end

   method los = writeVReg(los_wire);
   method mod0_presnt_n = writeVReg(mod0_presnt_n_wire);
   method txfault = writeVReg(txfault_wire);
   method ratesel0 = readVReg(ratesel0_wire);
   method ratesel1 = readVReg(ratesel1_wire);
   method txdisable = readVReg(txdisable_wire);
endmodule

interface De5Buttons#(numeric type nButtons);
   method Action pins((* port="" *) Vector#(nButtons, Bit#(1)) v);
(* prefix="", result="pressed" *)   method Vector#(nButtons, Bool) pressed;
endinterface

module mkDe5Buttons(De5Buttons#(nButtons));
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;
   Vector#(nButtons, Wire#(Bit#(1))) button_in <- replicateM(mkDWire(0));
   Vector#(nButtons, Wire#(Bool)) button_pressed <- replicateM(mkDWire(False));

   Vector#(4, PushButtonController) buttons <- replicateM(mkPushButtonController(defaultClock));
   for (Integer i=0; i<valueOf(nButtons); i=i+1) begin
      rule setPushButtonInput;
         buttons[i].ifc.button(button_in[i]);
      endrule

      rule setPushButtonParam;
         buttons[i].setRepeatParams(10, 10);
      endrule

      rule setPushButtonOutput;
         button_pressed[i] <= buttons[i].pressed;
      endrule
   end

   method pins = writeVReg(button_in);
   method pressed = readVReg(button_pressed);
endmodule


compilation fixes

compilation fixes

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

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

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

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

import FIFO::*;
import GetPutF::*;
import PortalRMemory::*;
import RingTypes::*;
import StmtFSM::*;

// The interface to the copyengine is a pair of fifos which supply and accept
// blocks of 8 64 bit words
// A Command:
//  word 0: COPY[63:56] TAG[31:0]
//  word 1: readAddress[39:0]
//  word 2: writeAddress[39:0]
//  word 3: bytecount[15:0'
//  word 4-7 unused
// Status
//  word0-6 all 0
//  word7  TAG[31:0]

module mkCopyEngine#(DMAReadClient#(64) copy_read_chan, DMAWriteClient#(64) copy_write_chan) ( ServerF#(Bit#(64), Bit#(64)));
   FIFO#(Bit#(64)) f_in  <- mkSizedFIFO(16);    // to buffer incoming requests
   FIFO#(Bit#(64)) f_out <- mkSizedFIFO(16);    // to buffer outgoing responses
   Reg#(Bit#(16)) copyReadCount <- mkReg(0);
   Reg#(Bit#(16)) copyWriteCount <- mkReg(0);
   Reg#(Bit#(40)) copyReadAddr <- mkReg(0);
   Reg#(Bit#(40)) copyWriteAddr <- mkReg(0);
   Reg#(Bit#(32)) copyTag <- mkReg(0);
   Reg#(Bool) copyBusy <- mkReg(False);

   Stmt copyStart =
   seq
      while(True)
	 seq
	    while (copyBusy) noAction;
	    copyTag <= f_in.deq[31:0];
	    copyReadAddr <= f_in.deq[39:0];
	    copyWriteAddr <= f_in.deq[39:0];
	    action
	       let regv <-f_in.deq[15:0];
	       copyReadCount <= regv;
	       copyWriteCount <= regv;
	    endaction
	    for (ii <= 0; ii < 4; ii <= ii+1)
	       f_in.deq;
	    copyBusy <= True;
	 endseq
   endseq;

    rule copyReadRule (copyBusy && (copyReadCount != 0));
       $display("copyRead %h, count %h", copyReadAddr, copyReadCount);
       copy_read_chan.readReq.put(copyReadAddr);
       copyReadAddr <= copyReadAddr + 8;
       copyReadCount <= copyReadCount - 8;
    endrule

    rule copyReadWriteRule (copyBusy);
       let data <- copy_read_chan.readData.get;
       $display("copyReadWrite addr %h", copyWriteAddr);
       copy_write_chan.writeReq.put(copyWriteAddr);
       copy_write_chan.writeData.put(data);
       copyWriteAddr <= copyWriteAddr + 8;
    endrule

   Stmt copyFinish =
   seq
      while(True)
	 seq
	    while (!copyBusy) noAction;
	    while (copyWriteCount > 0)
	       action
		  let v <- copy_write_chan.writeDone.get;
		  copyWriteCount <= copyWriteCount - 8;
	       endaction
	    for (ii <= 0; ii < 7; ii <= ii + 1)
	       f_out.enq(0);
	    f_out.enq(extend(copyTag));
	    copyBusy <= False;
	 endseq
   endseq;

   mkAutoFSM(copyStart);
   mkAutoFSM(copyFinish);

   interface PutF request = toPutF(f_in);
   interface GetF response = toGetF (f_out);

endmodule: mkCopyEngine

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

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

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

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

import FIFO::*;
import GetPutF::*;
import PortalRMemory::*;
import RingTypes::*;

// The interface to the copyengine is a pair of fifos which supply and accept
// blocks of 8 64 bit words
// A Command:
//  word 0: COPY[63:56] TAG[31:0]
//  word 1: readAddress[39:0]
//  word 2: writeAddress[39:0]
//  word 3: bytecount[15:0'
//  word 4-7 unused
// Status
//  word0-6 all 0
//  word7  TAG[31:0]

module mkCopyEngine#(ReadChan#(Bit#(64)) copy_read_chan, WriteChan#(Bit#(64)) copy_write_chan) ( ServerF#(Bit#(64), Bit#(64)));
   FIFO#(Bit#(64)) f_in  <- mkSizedFIFO(16);    // to buffer incoming requests
   FIFO#(Bit#(64)) f_out <- mkSizedFIFO(16);    // to buffer outgoing responses
   Reg#(Bit#(16)) copyReadCount <- mkReg(0);
   Reg#(Bit#(16)) copyWriteCount <- mkReg(0);
   Reg#(Bit#(40)) copyReadAddr <- mkReg(0);
   Reg#(Bit#(40)) copyWriteAddr <- mkReg(0);
   Reg#(Bit#(32)) copyTag <- mkReg(0);
   Reg#(Bool) copyBusy <- mkReg(False);

   Stmt copyStart =
   seq
      while(True)
	 seq
	    while (copyBusy) noAction;
	    copyTag <= f_in.deq[31:0];
	    copyReadAddr <= f_in.deq[39:0];
	    copyWriteAddr <= f_in.deq[39:0];
	    action
	       let regv <-f_in.deq[15:0];
	       copyReadCount <= regv;
	       copyWriteCount <= regv;
	    endaction
	    for (ii <= 0; ii < 4; ii <= ii+1)
	       f_in.deq;
	    copyBusy <= True;
	 endseq
   endseq

    rule copyReadRule (copyBusy && (copyReadCount != 0));
       $display("copyRead %h, count %h", copyReadAddr, copyReadCount);
       copy_read_chan.readReq.put(copyReadAddr);
       copyReadAddr <= copyReadAddr + 8;
       copyReadCount <= copyReadCount - 8;
    endrule

    rule copyReadWriteRule (copyBusy);
       let data <- copy_read_chan.readData.get;
       $display("copyReadWrite addr %h", copyWriteAddr);
       copy_write_chan.writeReq.put(copyWriteAddr);
       copy_write_chan.writeData.put(data);
       copyWriteAddr <= copyWriteAddr + 8;
    endrule

   Stmt copyFinish =
   seq
      while(True)
	 seq
	    while (!copyBusy) noAction;
	    while (copyWriteCount > 0)
	       action
		  let v <= copy_write_chan.writeDone.get;
		  copyWriteCount <= copyWriteCount - 8;
	       endaction
	    for (ii <= 0; ii < 7; ii += 1)
	       f_out.enq(0);
	    f_out.enq(extend(copyTag));
	    copyBusy <= False;
	 endseq
   endseq

   FSM start();
   mkAutoFSM#(copyStart)(start);
   FSM finish();
   mkAutoFSM#(copyFinish)(finish);

   interface PutF request = toPutF(f_in);
   interface GetF response = toGetF (f_out);

endmodule: mkCopyEngine


changed BsimHost so that it exports MemMaster instead of Axi3Master

// 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 FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import AxiMasterSlave    :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import Dma               :: *;
import AxiDma            :: *;

// implemented in BsimCtrl.cxx
import "BDPI" function Action      initPortal(Bit#(32) d);
import "BDPI" function Bool                    writeReq32();
import "BDPI" function ActionValue#(Bit#(32)) writeAddr32();
import "BDPI" function ActionValue#(Bit#(32)) writeData32();
import "BDPI" function Bool                     readReq32();
import "BDPI" function ActionValue#(Bit#(32))  readAddr32();
import "BDPI" function Action        readData32(Bit#(32) d);

// implemented in BsimDma.cxx
import "BDPI" function Action pareff(Bit#(32) handle, Bit#(32) size);
import "BDPI" function Action init_pareff();
import "BDPI" function Action write_pareff32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_pareff64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_pareff32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_pareff64(Bit#(32) handle, Bit#(32) addr);

interface BsimCtrlReadWrite#(numeric type asz, numeric type dsz);
   method ActionValue#(Bit#(asz)) readAddr();
   method Action readData(Bit#(dsz) d);
   method Bool readReq();
   method ActionValue#(Bit#(asz)) writeAddr();
   method ActionValue#(Bit#(dsz)) writeData();
   method Bool writeReq();
endinterface

typeclass SelectBsimCtrlReadWrite#(numeric type asz, numeric type dsz);
   module selectBsimCtrlReadWrite(BsimCtrlReadWrite#(asz,dsz) ifc);
endtypeclass

instance SelectBsimCtrlReadWrite#(32,32);
   module selectBsimCtrlReadWrite(BsimCtrlReadWrite#(32,32) ifc);
      method ActionValue#(Bit#(32)) readAddr();
	 let rv <- readAddr32();
	 return extend(rv);
      endmethod
      method Action readData(Bit#(32) d);
	 readData32(d);
      endmethod
      method Bool readReq();
	 return readReq32();
      endmethod
      method ActionValue#(Bit#(32)) writeAddr();
	 let rv <- writeAddr32();
	 return extend(rv);
      endmethod
      method ActionValue#(Bit#(32)) writeData();
	 let rv <- writeData32();
	 return rv;
      endmethod
      method Bool writeReq();
	 return writeReq32();
      endmethod
   endmodule
endinstance

interface BsimRdmaReadWrite#(numeric type dsz);
   method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(dsz) v);
   method ActionValue#(Bit#(dsz)) read_pareff(Bit#(32) handle, Bit#(32) addr);
endinterface

typeclass SelectBsimRdmaReadWrite#(numeric type dsz);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(dsz) ifc);
endtypeclass

instance SelectBsimRdmaReadWrite#(32);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(32) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
	  write_pareff32(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(32)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff32(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(64);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(64) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
	  write_pareff64(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(64)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff64(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(128);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(128) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(128) v);
	  write_pareff64(handle, addr, v[63:0]);
	  write_pareff64(handle, addr+8, v[127:64]);
       endmethod
       method ActionValue#(Bit#(128)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v0 <- read_pareff64(handle, addr);
	  let v1 <- read_pareff64(handle, addr+8);
	  return {v1,v0};
       endmethod
   endmodule
endinstance

// this interface should allow for different master and slave bus paraters;
interface BsimHost#(numeric type clientAddrWidth, numeric type clientBusWidth, numeric type clientIdWidth,
		    numeric type serverAddrWidth, numeric type serverBusWidth, numeric type serverIdWidth,
		    numeric type nSlaves);
   interface MemMaster#(clientAddrWidth, clientBusWidth)  mem_client;
   interface Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))  axi_servers;
endinterface

module mkAxi3Slave(Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth));

   BsimRdmaReadWrite#(serverBusWidth) rw <- selectBsimRdmaReadWrite();

   Reg#(Bit#(serverAddrWidth)) readAddrr <- mkReg(0);
   Reg#(Bit#(5))  readLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) readId <- mkReg(0);
   Reg#(Bit#(serverAddrWidth)) writeAddrr <- mkReg(0);
   Reg#(Bit#(5))  writeLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) writeId <- mkReg(0);

   Bit#(64) readLatency = 128;
   Bit#(64) writeLatency = 128;

   Reg#(Bit#(64)) req_ar_b_ts <- mkReg(0);
   Reg#(Bit#(64)) req_aw_b_ts <- mkReg(0);
   Reg#(Bit#(64)) cycle <- mkReg(0);
   Reg#(Bit#(64)) last_reqAr <- mkReg(0);
   Reg#(Bit#(64)) last_read_eob <- mkReg(0);
   Reg#(Bit#(64)) last_write_eob <- mkReg(0);

   Vector#(4,FIFOF#(Tuple2#(Bit#(64), Axi3ReadRequest#(serverAddrWidth,serverIdWidth)))) readDelayFifos <- replicateM(mkSizedFIFOF(16));
   let readDelayFifo = (readDelayFifos[3].notEmpty ? readDelayFifos[3] : (readDelayFifos[2].notEmpty ? readDelayFifos[2] : (readDelayFifos[1].notEmpty ? readDelayFifos[1] : readDelayFifos[0])));

   FIFOF#(Tuple2#(Bit#(64),Axi3WriteRequest#(serverAddrWidth,serverIdWidth))) writeDelayFifo <- mkSizedFIFOF(16);

   Vector#(4,FIFOF#(Tuple2#(Bit#(64), Axi3WriteResponse#(serverIdWidth)))) bFifos <- replicateM(mkSizedFIFOF(16));
   let bFifo = (bFifos[3].notEmpty ? bFifos[3] : (bFifos[2].notEmpty ? bFifos[2] : (bFifos[1].notEmpty ? bFifos[1] : bFifos[0])));

   rule increment_cycle;
      cycle <= cycle+1;
   endrule

   interface Put req_ar;
      method Action put(Axi3ReadRequest#(serverAddrWidth,serverIdWidth) req);
	 //$display("mkBsimHost::req_ar_a: %d %d", req.id, cycle-last_reqAr);
	 //last_reqAr <= cycle;
	 readDelayFifos[req.id[1:0]].enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(serverBusWidth,serverIdWidth)) get if ((readLen > 0) || (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency));
	 Bit#(5) read_len = ?;
	 Bit#(serverAddrWidth) read_addr = ?;
	 Bit#(serverIdWidth) read_id = ?;
	 Bit#(8) handle = ?;
	 if (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency) begin
	    req_ar_b_ts <= cycle;
	    let req = tpl_2(readDelayFifo.first);
	    readDelayFifo.deq;
	    read_len = extend(req.len)+1;
	    read_addr = req.address;
	    read_id = req.id;
	    handle = req.address[39:32];
	    //$display("mkBsimHost::resp_read_a: %d %d", req.id,  cycle-last_read_eob);
	    //last_read_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_read_b: %d %d", readId,  cycle-last_read_eob);
	    //last_read_eob <= cycle;
	    handle = readAddrr[39:32];
	    read_addr = readAddrr;
	    read_id = readId;
	    read_len = readLen;
	 end
	 Bit#(serverBusWidth) v <- rw.read_pareff(extend(handle), read_addr[31:0]);
	 readLen <= read_len - 1;
	 readId <= read_id;
	 readAddrr <= read_addr + fromInteger(valueOf(serverBusWidth)/8);
	 //$display("mkBsimHost::resp_read id=%d %d", read_id, read_len);
	 return Axi3ReadResponse { data: v, resp: 0, last: pack(readLen == 1), id: read_id};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(serverAddrWidth,serverIdWidth) req);
	 //$display("mkBsimHost::req_aw id=%d", req.id);
	 writeDelayFifo.enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(serverBusWidth,serverIdWidth) resp) if ((writeLen > 0) || (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency));
	 Bit#(5) write_len = ?;
	 Bit#(serverAddrWidth) write_addr = ?;
	 Bit#(serverIdWidth) write_id = ?;
	 Bit#(8) handle = ?;
	 if (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency) begin
	    req_aw_b_ts <= cycle;
	    let req = tpl_2(writeDelayFifo.first);
	    writeDelayFifo.deq;
	    write_addr = req.address;
	    write_len = extend(req.len)+1;
	    write_id = req.id;
	    handle = req.address[39:32];
	    //$display("mkBsimHost::resp_write_a: %d %d", req.id,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_write_b: %d %d", writeId,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	    handle = writeAddrr[39:32];
	    write_len = writeLen;
	    write_addr = writeAddrr;
	    write_id = writeId;
	 end
	 rw.write_pareff(extend(handle), write_addr[31:0], resp.data);
	 //$display("write_resp(%d): handle=%d addr=%h v=%h", cycle, handle, write_addr, resp.data);
	 writeId <= write_id;
	 writeLen <= write_len - 1;
	 writeAddrr <= write_addr + fromInteger(valueOf(serverBusWidth)/8);
	 if (write_len == 1) begin
	    bFifos[write_id[1:0]].enq(tuple2(cycle,Axi3WriteResponse { id: write_id, resp: 0 }));
	 end
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(serverIdWidth)) get if ((cycle-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
      endmethod
   endinterface

endmodule

module [Module] mkBsimHost (BsimHost#(clientAddrWidth, clientBusWidth, clientIdWidth,
				      serverAddrWidth, serverBusWidth, serverIdWidth,
				      nSlaves))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth),
	     SelectBsimCtrlReadWrite#(clientAddrWidth, clientBusWidth));

   Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth)) servers <- replicateM(mkAxi3Slave);
   BsimCtrlReadWrite#(clientAddrWidth,clientBusWidth) crw <- selectBsimCtrlReadWrite();
   FIFO#(Bit#(clientBusWidth)) wf <- mkPipelineFIFO;
   let init_seq = (action
		      initPortal(0);
		      initPortal(1);
		      initPortal(2);
		      initPortal(3);
		      initPortal(4);
		      initPortal(5);
		      initPortal(6);
		      initPortal(7);
                   endaction);
   let init_fsm <- mkOnce(init_seq);

   rule init_rule;
      init_pareff();
      init_fsm.start;
   endrule

   interface axi_servers = servers;
   interface MemMaster mem_client;
      interface MemReadClient read_client;
        interface Get readReq;
	 method ActionValue#(MemRequest#(clientAddrWidth)) get() if (crw.readReq);
	    //$write("req_ar: ");
	    let ra <- crw.readAddr;
	    //$display("ra=%h", ra);
	    return MemRequest { addr: ra, burstLen: 1, tag: 0};
	 endmethod
        endinterface
        interface Put readData;
	 method Action put(MemData#(clientBusWidth) rd);
	    //$display("resp_read: rd=%h", rd);
	    crw.readData(rd.data);
	 endmethod
        endinterface
      endinterface
      interface MemWriteClient write_client;
        interface Get writeReq;
	 method ActionValue#(MemRequest#(clientAddrWidth)) get() if (crw.writeReq());
	    //$write("req_aw: ");
	    let wa <- crw.writeAddr;
	    let wd <- crw.writeData;
	    //$display("wa=%h, wd=%h", wa,wd);
	    wf.enq(wd);
	    return MemRequest { addr: wa, burstLen: 1, tag: 0 };
	 endmethod
        endinterface
        interface Get writeData;
	 method ActionValue#(MemData#(clientBusWidth)) get;
	    wf.deq;
	    //$display("resp_write %h", wf.first);
	    return MemData { data: wf.first, tag: 0};
	 endmethod
        endinterface
        interface Put writeDone;
	 method Action put(Bit#(ObjectTagSize) resp);
	    noAction;
	 endmethod
        endinterface
      endinterface
   endinterface
endmodule

typedef (function Module#(PortalTop#(40, dsz, ipins, nMasters)) mkPortalTop()) MkPortalTop#(numeric type dsz, type ipins, numeric type nMasters);

module [Module] mkBsimTopFromPortal#(MkPortalTop#(dsz,Empty,nMasters) mkPortalTop)(Empty)
   provisos (SelectBsimRdmaReadWrite#(dsz),
	     Mul#(TDiv#(dsz, 8), 8, dsz));
   BsimHost#(32,32,12,40,dsz,6,nMasters) host <- mkBsimHost;
   PortalTop#(40,dsz,Empty,nMasters) top <- mkPortalTop;
   Vector#(nMasters,Axi3Master#(40,dsz,6)) m_axis <- mapM(mkAxiDmaMaster,top.masters);
   mkConnection(host.mem_client, top.slave);
   mapM(uncurry(mkConnection),zip(m_axis, host.axi_servers));

   // mkConnection(m_axis[0].req_ar, host.axi_servers[0].req_ar);
   // mkConnection(host.axi_servers[0].resp_read, m_axis[0].resp_read);
   // rule yyy;
   //    let rv <- host.axi_servers[0].resp_read.get;
   // endrule
   // rule xxx;
   //          m_axis[0].resp_read.put(unpack(0));
   // endrule

endmodule

module mkBsimTop(Empty);
   let top <- mkBsimTopFromPortal(mkPortalTop);
   return top;
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 FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import AxiMasterSlave    :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import AxiDma            :: *;

// implemented in BsimCtrl.cxx
import "BDPI" function Action      initPortal(Bit#(32) d);
import "BDPI" function Bool                    writeReq32();
import "BDPI" function ActionValue#(Bit#(32)) writeAddr32();
import "BDPI" function ActionValue#(Bit#(32)) writeData32();
import "BDPI" function Bool                     readReq32();
import "BDPI" function ActionValue#(Bit#(32))  readAddr32();
import "BDPI" function Action        readData32(Bit#(32) d);

// implemented in BsimDma.cxx
import "BDPI" function Action pareff(Bit#(32) handle, Bit#(32) size);
import "BDPI" function Action init_pareff();
import "BDPI" function Action write_pareff32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_pareff64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_pareff32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_pareff64(Bit#(32) handle, Bit#(32) addr);

interface BsimCtrlReadWrite#(numeric type asz, numeric type dsz);
   method ActionValue#(Bit#(asz)) readAddr();
   method Action readData(Bit#(dsz) d);
   method Bool readReq();
   method ActionValue#(Bit#(asz)) writeAddr();
   method ActionValue#(Bit#(dsz)) writeData();
   method Bool writeReq();
endinterface

typeclass SelectBsimCtrlReadWrite#(numeric type asz, numeric type dsz);
   module selectBsimCtrlReadWrite(BsimCtrlReadWrite#(asz,dsz) ifc);
endtypeclass

instance SelectBsimCtrlReadWrite#(32,32);
   module selectBsimCtrlReadWrite(BsimCtrlReadWrite#(32,32) ifc);
      method ActionValue#(Bit#(32)) readAddr();
	 let rv <- readAddr32();
	 return extend(rv);
      endmethod
      method Action readData(Bit#(32) d);
	 readData32(d);
      endmethod
      method Bool readReq();
	 return readReq32();
      endmethod
      method ActionValue#(Bit#(32)) writeAddr();
	 let rv <- writeAddr32();
	 return extend(rv);
      endmethod
      method ActionValue#(Bit#(32)) writeData();
	 let rv <- writeData32();
	 return rv;
      endmethod
      method Bool writeReq();
	 return writeReq32();
      endmethod
   endmodule
endinstance

interface BsimRdmaReadWrite#(numeric type dsz);
   method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(dsz) v);
   method ActionValue#(Bit#(dsz)) read_pareff(Bit#(32) handle, Bit#(32) addr);
endinterface

typeclass SelectBsimRdmaReadWrite#(numeric type dsz);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(dsz) ifc);
endtypeclass

instance SelectBsimRdmaReadWrite#(32);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(32) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
	  write_pareff32(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(32)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff32(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(64);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(64) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
	  write_pareff64(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(64)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff64(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(128);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(128) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(128) v);
	  write_pareff64(handle, addr, v[63:0]);
	  write_pareff64(handle, addr+8, v[127:64]);
       endmethod
       method ActionValue#(Bit#(128)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v0 <- read_pareff64(handle, addr);
	  let v1 <- read_pareff64(handle, addr+8);
	  return {v1,v0};
       endmethod
   endmodule
endinstance

// this interface should allow for different master and slave bus paraters;
interface BsimHost#(numeric type clientAddrWidth, numeric type clientBusWidth, numeric type clientIdWidth,
		    numeric type serverAddrWidth, numeric type serverBusWidth, numeric type serverIdWidth,
		    numeric type nSlaves);
   interface Axi3Master#(clientAddrWidth, clientBusWidth, clientIdWidth)  axi_client;
   interface Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))  axi_servers;
endinterface

module mkAxi3Slave(Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth));

   BsimRdmaReadWrite#(serverBusWidth) rw <- selectBsimRdmaReadWrite();

   Reg#(Bit#(serverAddrWidth)) readAddrr <- mkReg(0);
   Reg#(Bit#(5))  readLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) readId <- mkReg(0);
   Reg#(Bit#(serverAddrWidth)) writeAddrr <- mkReg(0);
   Reg#(Bit#(5))  writeLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) writeId <- mkReg(0);

   Bit#(64) readLatency = 128;
   Bit#(64) writeLatency = 128;

   Reg#(Bit#(64)) req_ar_b_ts <- mkReg(0);
   Reg#(Bit#(64)) req_aw_b_ts <- mkReg(0);
   Reg#(Bit#(64)) cycle <- mkReg(0);
   Reg#(Bit#(64)) last_reqAr <- mkReg(0);
   Reg#(Bit#(64)) last_read_eob <- mkReg(0);
   Reg#(Bit#(64)) last_write_eob <- mkReg(0);

   Vector#(4,FIFOF#(Tuple2#(Bit#(64), Axi3ReadRequest#(serverAddrWidth,serverIdWidth)))) readDelayFifos <- replicateM(mkSizedFIFOF(16));
   let readDelayFifo = (readDelayFifos[3].notEmpty ? readDelayFifos[3] : (readDelayFifos[2].notEmpty ? readDelayFifos[2] : (readDelayFifos[1].notEmpty ? readDelayFifos[1] : readDelayFifos[0])));

   FIFOF#(Tuple2#(Bit#(64),Axi3WriteRequest#(serverAddrWidth,serverIdWidth))) writeDelayFifo <- mkSizedFIFOF(16);

   Vector#(4,FIFOF#(Tuple2#(Bit#(64), Axi3WriteResponse#(serverIdWidth)))) bFifos <- replicateM(mkSizedFIFOF(16));
   let bFifo = (bFifos[3].notEmpty ? bFifos[3] : (bFifos[2].notEmpty ? bFifos[2] : (bFifos[1].notEmpty ? bFifos[1] : bFifos[0])));

   rule increment_cycle;
      cycle <= cycle+1;
   endrule

   interface Put req_ar;
      method Action put(Axi3ReadRequest#(serverAddrWidth,serverIdWidth) req);
	 //$display("mkBsimHost::req_ar_a: %d %d", req.id, cycle-last_reqAr);
	 //last_reqAr <= cycle;
	 readDelayFifos[req.id[1:0]].enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(serverBusWidth,serverIdWidth)) get if ((readLen > 0) || (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency));
	 Bit#(5) read_len = ?;
	 Bit#(serverAddrWidth) read_addr = ?;
	 Bit#(serverIdWidth) read_id = ?;
	 Bit#(8) handle = ?;
	 if (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency) begin
	    req_ar_b_ts <= cycle;
	    let req = tpl_2(readDelayFifo.first);
	    readDelayFifo.deq;
	    read_len = extend(req.len)+1;
	    read_addr = req.address;
	    read_id = req.id;
	    handle = req.address[39:32];
	    //$display("mkBsimHost::resp_read_a: %d %d", req.id,  cycle-last_read_eob);
	    //last_read_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_read_b: %d %d", readId,  cycle-last_read_eob);
	    //last_read_eob <= cycle;
	    handle = readAddrr[39:32];
	    read_addr = readAddrr;
	    read_id = readId;
	    read_len = readLen;
	 end
	 Bit#(serverBusWidth) v <- rw.read_pareff(extend(handle), read_addr[31:0]);
	 readLen <= read_len - 1;
	 readId <= read_id;
	 readAddrr <= read_addr + fromInteger(valueOf(serverBusWidth)/8);
	 //$display("mkBsimHost::resp_read id=%d %d", read_id, read_len);
	 return Axi3ReadResponse { data: v, resp: 0, last: pack(readLen == 1), id: read_id};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(serverAddrWidth,serverIdWidth) req);
	 //$display("mkBsimHost::req_aw id=%d", req.id);
	 writeDelayFifo.enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(serverBusWidth,serverIdWidth) resp) if ((writeLen > 0) || (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency));
	 Bit#(5) write_len = ?;
	 Bit#(serverAddrWidth) write_addr = ?;
	 Bit#(serverIdWidth) write_id = ?;
	 Bit#(8) handle = ?;
	 if (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency) begin
	    req_aw_b_ts <= cycle;
	    let req = tpl_2(writeDelayFifo.first);
	    writeDelayFifo.deq;
	    write_addr = req.address;
	    write_len = extend(req.len)+1;
	    write_id = req.id;
	    handle = req.address[39:32];
	    //$display("mkBsimHost::resp_write_a: %d %d", req.id,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_write_b: %d %d", writeId,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	    handle = writeAddrr[39:32];
	    write_len = writeLen;
	    write_addr = writeAddrr;
	    write_id = writeId;
	 end
	 rw.write_pareff(extend(handle), write_addr[31:0], resp.data);
	 //$display("write_resp(%d): handle=%d addr=%h v=%h", cycle, handle, write_addr, resp.data);
	 writeId <= write_id;
	 writeLen <= write_len - 1;
	 writeAddrr <= write_addr + fromInteger(valueOf(serverBusWidth)/8);
	 if (write_len == 1) begin
	    bFifos[write_id[1:0]].enq(tuple2(cycle,Axi3WriteResponse { id: write_id, resp: 0 }));
	 end
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(serverIdWidth)) get if ((cycle-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
      endmethod
   endinterface

endmodule

module [Module] mkBsimHost (BsimHost#(clientAddrWidth, clientBusWidth, clientIdWidth,
				      serverAddrWidth, serverBusWidth, serverIdWidth,
				      nSlaves))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth),
	     SelectBsimCtrlReadWrite#(clientAddrWidth, clientBusWidth));

   Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth)) servers <- replicateM(mkAxi3Slave);
   BsimCtrlReadWrite#(clientAddrWidth,clientBusWidth) crw <- selectBsimCtrlReadWrite();
   FIFO#(Bit#(clientBusWidth)) wf <- mkPipelineFIFO;
   let init_seq = (action
		      initPortal(0);
		      initPortal(1);
		      initPortal(2);
		      initPortal(3);
		      initPortal(4);
		      initPortal(5);
		      initPortal(6);
		      initPortal(7);
                   endaction);
   let init_fsm <- mkOnce(init_seq);

   rule init_rule;
      init_pareff();
      init_fsm.start;
   endrule

   interface axi_servers = servers;
   interface Axi3Master axi_client;
      interface Get req_ar;
	 method ActionValue#(Axi3ReadRequest#(clientAddrWidth,clientIdWidth)) get() if (crw.readReq);
	    //$write("req_ar: ");
	    let ra <- crw.readAddr;
	    //$display("ra=%h", ra);
	    return Axi3ReadRequest { address: ra, len: 0, size: axiBusSize(32), id: 0, prot: 0, burst: 1, cache: 'b11, qos: 0, lock: 0 };
	 endmethod
      endinterface
      interface Put resp_read;
	 method Action put(Axi3ReadResponse#(clientBusWidth,clientIdWidth) rd);
	    //$display("resp_read: rd=%h", rd);
	    crw.readData(rd.data);
	 endmethod
      endinterface
      interface Get req_aw;
	 method ActionValue#(Axi3WriteRequest#(clientAddrWidth,clientIdWidth)) get() if (crw.writeReq());
	    //$write("req_aw: ");
	    let wa <- crw.writeAddr;
	    let wd <- crw.writeData;
	    //$display("wa=%h, wd=%h", wa,wd);
	    wf.enq(wd);
	    return Axi3WriteRequest { address: wa, len: 0, size: axiBusSize(32), id: 0, prot: 0, burst: 1, cache: 'b11, qos: 0, lock: 0 };
	 endmethod
      endinterface
      interface Get resp_write;
	 method ActionValue#(Axi3WriteData#(clientBusWidth,clientIdWidth)) get;
	    wf.deq;
	    //$display("resp_write %h", wf.first);
	    return Axi3WriteData { data: wf.first, id: 0, last: 1 };
	 endmethod
      endinterface
      interface Put resp_b;
	 method Action put(Axi3WriteResponse#(clientIdWidth) resp);
	    noAction;
	 endmethod
      endinterface
   endinterface
endmodule

typedef (function Module#(PortalTop#(40, dsz, ipins, nMasters)) mkPortalTop()) MkPortalTop#(numeric type dsz, type ipins, numeric type nMasters);

module [Module] mkBsimTopFromPortal#(MkPortalTop#(dsz,Empty,nMasters) mkPortalTop)(Empty)
   provisos (SelectBsimRdmaReadWrite#(dsz),
	     Mul#(TDiv#(dsz, 8), 8, dsz));
   BsimHost#(32,32,12,40,dsz,6,nMasters) host <- mkBsimHost;
   PortalTop#(40,dsz,Empty,nMasters) top <- mkPortalTop;
   Vector#(nMasters,Axi3Master#(40,dsz,6)) m_axis <- mapM(mkAxiDmaMaster,top.masters);
   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(top.slave);
   mkConnection(host.axi_client, ctrl);
   mapM(uncurry(mkConnection),zip(m_axis, host.axi_servers));

   // mkConnection(m_axis[0].req_ar, host.axi_servers[0].req_ar);
   // mkConnection(host.axi_servers[0].resp_read, m_axis[0].resp_read);
   // rule yyy;
   //    let rv <- host.axi_servers[0].resp_read.get;
   // endrule
   // rule xxx;
   //          m_axis[0].resp_read.put(unpack(0));
   // endrule

endmodule

module mkBsimTop(Empty);
   let top <- mkBsimTopFromPortal(mkPortalTop);
   return top;
endmodule