added newly required provisos FunnelPipesPipelined to strstr

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import Gearbox::*;
import Connectable::*;
import StmtFSM::*;
import MemTypes::*;
import MPEngine::*;
import MemReadEngine::*;
import Pipe::*;

interface StrstrRequest;
   method Action setup(Bit#(32) needleSGLId, Bit#(32) mpNextSGLId, Bit#(32) needle_len);
   method Action search(Bit#(32) haystackSGLId, Bit#(32) haystack_len);
endinterface

interface StrstrIndication;
   method Action searchResult(Int#(32) v);
endinterface

interface Strstr#(numeric type haystackBusWidth, numeric type configBusWidth);
   interface StrstrRequest request;
   interface Vector#(1, MemReadClient#(haystackBusWidth)) haystack_read_client;
   interface Vector#(1, MemReadClient#(configBusWidth)) config_read_client;
endinterface

// I can't belive we still have to do this shit
function Bool my_or(Bool a, Bool b) = a || b;

typedef `DEGPAR DegPar;

module mkStrstr#(StrstrIndication indication)(Strstr#(haystackBusWidth, configBusWidth))
   provisos( Log#(DegPar,logDegPar)

   ,Mul#(TDiv#(configBusWidth, 8), 8, configBusWidth)
   ,Mul#(TDiv#(haystackBusWidth, 8), 8, haystackBusWidth)
   ,Add#(1, a__, TDiv#(haystackBusWidth, 8))
   ,Add#(b__, TLog#(TDiv#(haystackBusWidth, 8)), 32)
   ,Mul#(TDiv#(configBusWidth, 32), 32, configBusWidth)
   ,Add#(1, c__, TDiv#(configBusWidth, 32))
   ,Add#(d__, TLog#(TDiv#(configBusWidth, 32)), 32)
   ,Add#(e__, TLog#(TDiv#(configBusWidth, 8)), 32)
   ,Add#(1, f__, TDiv#(configBusWidth, 8))
   ,Add#(g__, TLog#(TDiv#(haystackBusWidth, 32)), 32)
   ,Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth)
   ,Add#(1, h__, TDiv#(haystackBusWidth, 32))
   ,Add#(i__, 32, haystackBusWidth)
   ,Add#(j__, 8, haystackBusWidth)
   ,FunnelPipesPipelined#(1, DegPar, MemData#(haystackBusWidth), MemReadFunnelBPC)
   ,FunnelPipesPipelined#(1, DegPar, MemData#(configBusWidth), MemReadFunnelBPC)
	    );

   let verbose = True;

   Reg#(Bit#(32)) needleLen <- mkReg(0);
   MemReadEngine#(haystackBusWidth,haystackBusWidth,1,DegPar) haystack_re <- mkMemReadEngineBuff(1024);
   MemReadEngine#(configBusWidth,configBusWidth,1,DegPar) config_re <- mkMemReadEngineBuff(1024);

   Reg#(Bit#(32)) needleSGLId <- mkReg(0);
   Reg#(Bit#(32)) mpNextSGLId <- mkReg(0);
   Reg#(Bit#(32)) haystackSGLId <- mkReg(0);
   Reg#(Bit#(32)) haystackLen <- mkReg(0);
   Reg#(Bit#(32)) startCnt <- mkReg(0);
   Reg#(Bit#(32)) startBase <- mkReg(0);
   Reg#(Bit#(32)) setupCnt <- mkReg(0);
   Reg#(Bit#(32)) doneCnt <- mkReg(0);

   let read_servers = zip(haystack_re.readServers,config_re.readServers);
   Vector#(DegPar, MPEngine#(haystackBusWidth,configBusWidth)) engines <- mapM(uncurry(mkMPEngine),read_servers);
   Vector#(DegPar, PipeOut#(Int#(32))) locdonePipes;

   FIFOF#(Tripple#(Bit#(32))) setsearchFIFO <- mkFIFOF;
   UnFunnelPipe#(1,DegPar,Tripple#(Bit#(32)),1) setsearchPipeUnFunnel <- mkUnFunnelPipesPipelinedRR(cons(toPipeOut(setsearchFIFO),nil), 1);

   for(Integer i = 0; i < valueOf(DegPar); i=i+1) begin
      locdonePipes[i] = engines[i].locdone;
      mkConnection(setsearchPipeUnFunnel[i],engines[i].setsearch);
   end

   FunnelPipe#(1,DegPar,Int#(32),1) locdonePipe <- mkFunnelPipesPipelined(locdonePipes);
   let lpv = fromInteger(valueOf(logDegPar));
   let pv = fromInteger(valueOf(DegPar));

   rule resr;
      let rv <- toGet(locdonePipe[0]).get;
      if (rv == -1) begin
	 // notify the SW when the search is finished
	 if (doneCnt+1 == pv) begin
	    doneCnt <= 0;
	    indication.searchResult(-1);
	 end
	 else begin
	    doneCnt <= doneCnt+1;
	 end
      end
      else begin
	 // send results back to SW
	 indication.searchResult(rv);
	 if (verbose) $display("strstr search result %d", rv);
      end
   endrule

   // setup the MPEngines when new configuration arrives
   Stmt setupStmt =
   seq
      action
	 if (verbose) $display("setupStmt (begin)");
	 setupCnt <= 0;
      endaction
      while(setupCnt < pv) action
	 setupCnt <= setupCnt+1;
	 let tup = tuple3(needleSGLId, mpNextSGLId, needleLen);
	 setsearchFIFO.enq(tup);
	 if (verbose) $display(fshow("setupStmt (mid) ")+fshow(tup));
      endaction
      if (verbose) $display("setupStmt (end)");
   endseq;
   FSM setupFSM <- mkFSM(setupStmt);

   // start the search;
   Stmt startStmt =
   seq
      action
	 if (verbose) $display("startStmt (begin)");
	 startCnt <= 0;
	 startBase <= 0;
      endaction
      while (startCnt < pv-1) action
	 let tup = tuple3(haystackSGLId, (haystackLen>>lpv)+needleLen, startBase);
	 setsearchFIFO.enq(tup);
	 startBase <= startBase + (haystackLen>>lpv);
	 startCnt <= startCnt+1;
	 if (verbose) $display(fshow("startStmt ")+fshow(tup)+fshow(" (mid)"));
      endaction
      action
	 let tup = tuple3(haystackSGLId, haystackLen>>lpv, startBase);
	 setsearchFIFO.enq(tup);
	 if (verbose) $display(fshow("startStmt ")+fshow(tup)+fshow(" (end)"));
      endaction
   endseq;
   FSM startFSM <- mkFSM(startStmt);

   interface StrstrRequest request;
      method Action setup(Bit#(32) needle_sglId, Bit#(32) mpNext_sglId, Bit#(32) needle_len);
	 if (verbose) $display("mkStrstr::setup %d %d %d", needle_sglId, mpNext_sglId, needle_len);
	 needleLen <= needle_len;
	 needleSGLId <= needle_sglId;
	 mpNextSGLId <= mpNext_sglId;
	 setupFSM.start();
      endmethod

      method Action search(Bit#(32) haystack_sglId, Bit#(32) haystack_len);
	 if (verbose) $display("mkStrstr::search %d %d", haystack_sglId, haystack_len);
	 haystackLen <= haystack_len;
	 haystackSGLId <= haystack_sglId;
	 startFSM.start();
      endmethod
   endinterface
   interface config_read_client = cons(config_re.dmaClient, nil);
   interface haystack_read_client = cons(haystack_re.dmaClient, nil);
endmodule

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import Gearbox::*;
import Connectable::*;
import StmtFSM::*;
import MemTypes::*;
import MPEngine::*;
import MemReadEngine::*;
import Pipe::*;

interface StrstrRequest;
   method Action setup(Bit#(32) needleSGLId, Bit#(32) mpNextSGLId, Bit#(32) needle_len);
   method Action search(Bit#(32) haystackSGLId, Bit#(32) haystack_len);
endinterface

interface StrstrIndication;
   method Action searchResult(Int#(32) v);
endinterface

interface Strstr#(numeric type haystackBusWidth, numeric type configBusWidth);
   interface StrstrRequest request;
   interface Vector#(1, MemReadClient#(haystackBusWidth)) haystack_read_client;
   interface Vector#(1, MemReadClient#(configBusWidth)) config_read_client;
endinterface

// I can't belive we still have to do this shit
function Bool my_or(Bool a, Bool b) = a || b;

typedef `DEGPAR DegPar;

module mkStrstr#(StrstrIndication indication)(Strstr#(haystackBusWidth, configBusWidth))
   provisos( Log#(DegPar,logDegPar)

   ,Mul#(TDiv#(configBusWidth, 8), 8, configBusWidth)
   ,Mul#(TDiv#(haystackBusWidth, 8), 8, haystackBusWidth)
   ,Add#(1, a__, TDiv#(haystackBusWidth, 8))
   ,Add#(b__, TLog#(TDiv#(haystackBusWidth, 8)), 32)
   ,Mul#(TDiv#(configBusWidth, 32), 32, configBusWidth)
   ,Add#(1, c__, TDiv#(configBusWidth, 32))
   ,Add#(d__, TLog#(TDiv#(configBusWidth, 32)), 32)
   ,Add#(e__, TLog#(TDiv#(configBusWidth, 8)), 32)
   ,Add#(1, f__, TDiv#(configBusWidth, 8))
   ,Add#(g__, TLog#(TDiv#(haystackBusWidth, 32)), 32)
   ,Mul#(TDiv#(haystackBusWidth, 32), 32, haystackBusWidth)
   ,Add#(1, h__, TDiv#(haystackBusWidth, 32))
   ,Add#(i__, 32, haystackBusWidth)
   ,Add#(j__, 8, haystackBusWidth)
	    );

   let verbose = True;

   Reg#(Bit#(32)) needleLen <- mkReg(0);
   MemReadEngine#(haystackBusWidth,haystackBusWidth,1,DegPar) haystack_re <- mkMemReadEngineBuff(1024);
   MemReadEngine#(configBusWidth,configBusWidth,1,DegPar) config_re <- mkMemReadEngineBuff(1024);

   Reg#(Bit#(32)) needleSGLId <- mkReg(0);
   Reg#(Bit#(32)) mpNextSGLId <- mkReg(0);
   Reg#(Bit#(32)) haystackSGLId <- mkReg(0);
   Reg#(Bit#(32)) haystackLen <- mkReg(0);
   Reg#(Bit#(32)) startCnt <- mkReg(0);
   Reg#(Bit#(32)) startBase <- mkReg(0);
   Reg#(Bit#(32)) setupCnt <- mkReg(0);
   Reg#(Bit#(32)) doneCnt <- mkReg(0);

   let read_servers = zip(haystack_re.readServers,config_re.readServers);
   Vector#(DegPar, MPEngine#(haystackBusWidth,configBusWidth)) engines <- mapM(uncurry(mkMPEngine),read_servers);
   Vector#(DegPar, PipeOut#(Int#(32))) locdonePipes;

   FIFOF#(Tripple#(Bit#(32))) setsearchFIFO <- mkFIFOF;
   UnFunnelPipe#(1,DegPar,Tripple#(Bit#(32)),1) setsearchPipeUnFunnel <- mkUnFunnelPipesPipelinedRR(cons(toPipeOut(setsearchFIFO),nil), 1);

   for(Integer i = 0; i < valueOf(DegPar); i=i+1) begin
      locdonePipes[i] = engines[i].locdone;
      mkConnection(setsearchPipeUnFunnel[i],engines[i].setsearch);
   end

   FunnelPipe#(1,DegPar,Int#(32),1) locdonePipe <- mkFunnelPipesPipelined(locdonePipes);
   let lpv = fromInteger(valueOf(logDegPar));
   let pv = fromInteger(valueOf(DegPar));

   rule resr;
      let rv <- toGet(locdonePipe[0]).get;
      if (rv == -1) begin
	 // notify the SW when the search is finished
	 if (doneCnt+1 == pv) begin
	    doneCnt <= 0;
	    indication.searchResult(-1);
	 end
	 else begin
	    doneCnt <= doneCnt+1;
	 end
      end
      else begin
	 // send results back to SW
	 indication.searchResult(rv);
	 if (verbose) $display("strstr search result %d", rv);
      end
   endrule

   // setup the MPEngines when new configuration arrives
   Stmt setupStmt =
   seq
      action
	 if (verbose) $display("setupStmt (begin)");
	 setupCnt <= 0;
      endaction
      while(setupCnt < pv) action
	 setupCnt <= setupCnt+1;
	 let tup = tuple3(needleSGLId, mpNextSGLId, needleLen);
	 setsearchFIFO.enq(tup);
	 if (verbose) $display(fshow("setupStmt (mid) ")+fshow(tup));
      endaction
      if (verbose) $display("setupStmt (end)");
   endseq;
   FSM setupFSM <- mkFSM(setupStmt);

   // start the search;
   Stmt startStmt =
   seq
      action
	 if (verbose) $display("startStmt (begin)");
	 startCnt <= 0;
	 startBase <= 0;
      endaction
      while (startCnt < pv-1) action
	 let tup = tuple3(haystackSGLId, (haystackLen>>lpv)+needleLen, startBase);
	 setsearchFIFO.enq(tup);
	 startBase <= startBase + (haystackLen>>lpv);
	 startCnt <= startCnt+1;
	 if (verbose) $display(fshow("startStmt ")+fshow(tup)+fshow(" (mid)"));
      endaction
      action
	 let tup = tuple3(haystackSGLId, haystackLen>>lpv, startBase);
	 setsearchFIFO.enq(tup);
	 if (verbose) $display(fshow("startStmt ")+fshow(tup)+fshow(" (end)"));
      endaction
   endseq;
   FSM startFSM <- mkFSM(startStmt);

   interface StrstrRequest request;
      method Action setup(Bit#(32) needle_sglId, Bit#(32) mpNext_sglId, Bit#(32) needle_len);
	 if (verbose) $display("mkStrstr::setup %d %d %d", needle_sglId, mpNext_sglId, needle_len);
	 needleLen <= needle_len;
	 needleSGLId <= needle_sglId;
	 mpNextSGLId <= mpNext_sglId;
	 setupFSM.start();
      endmethod

      method Action search(Bit#(32) haystack_sglId, Bit#(32) haystack_len);
	 if (verbose) $display("mkStrstr::search %d %d", haystack_sglId, haystack_len);
	 haystackLen <= haystack_len;
	 haystackSGLId <= haystack_sglId;
	 startFSM.start();
      endmethod
   endinterface
   interface config_read_client = cons(config_re.dmaClient, nil);
   interface haystack_read_client = cons(haystack_re.dmaClient, nil);
endmodule


added mkReducePipe

added mkReducePipe

// 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 FIFOF::*;
import GetPut::*;
import Connectable::*;
import Vector::*;
import MIMO::*;
import DefaultValue::*;

interface PipeOut#(type a);
   method a first();
   method Action deq();
   method Bool notEmpty();
endinterface

typeclass PipeInOut#(type a, type b);
   function PipeOut#(a) toPipeOut(b in);
endtypeclass

typeclass MkPipeInOut#(type a, type b);
   module mkPipeOut#(b in)(PipeOut#(a));
endtypeclass

instance PipeInOut#(a, FIFOF#(a));
   function PipeOut#(a) toPipeOut(FIFOF#(a) in);
      return (interface PipeOut#(a);
		 method first = in.first;
		 method deq = in.deq;
		 method notEmpty = in.notEmpty;
	      endinterface);
   endfunction
endinstance

instance MkPipeInOut#(a, Get#(a))
   provisos (Bits#(a, asz));
   module mkPipeOut#(Get#(a) in)(PipeOut#(a));
      FIFOF#(a) fifo <- mkFIFOF();
      rule connect;
	 let v <- in.get();
	 fifo.enq(v);
      endrule
      return toPipeOut(fifo);
   endmodule
endinstance

instance Connectable#(PipeOut#(a),Put#(a));
   module mkConnection#(PipeOut#(a) in, Put#(a) out)(Empty);
      rule connect;
	 let v = in.first;
	 in.deq();
	 out.put(v);
      endrule
   endmodule
endinstance

module mkUnfunnel#(PipeOut#(Vector#(m,a)) in)(PipeOut#(Vector#(mk, a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Add#(1, b__, asz),
	     Add#(2, c__, mk),
	     Add#(d__, m, mk),
	     Add#(asz, m, e__),
	     Add#(asz, mk, f__));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   MIMOConfiguration cfg = defaultValue();
   MIMO#(m, mk, mk, a) mimo <- mkMIMO(cfg);
   rule consumer if (mimo.enqReadyN(m));
      Vector#(m, a) v = in.first();
      in.deq();
      mimo.enq(m, v);
   endrule

   method Vector#(mk, a) first() if (mimo.deqReadyN(mk));
      return mimo.first();
   endmethod
   method Action deq() if (mimo.deqReadyN(mk));
      mimo.deq(mk);
   endmethod
   method notEmpty();
      return mimo.deqReadyN(mk);
   endmethod
endmodule

module mkForkVector#(PipeOut#(a) inpipe)(Vector#(n, PipeOut#(a)))
   provisos (Bits#(a, asz));
   Vector#(n, FIFOF#(a)) fifos <- replicateM(mkFIFOF());
   rule forkelts;
      let v = inpipe.first();
      inpipe.deq;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 fifos[i].enq(v);
      end
   endrule
   return map(toPipeOut, fifos);
endmodule

module mkJoin#(function c f(a av, b bv), PipeOut#(a) apipe, PipeOut#(b) bpipe)(PipeOut#(c));
   method c first();
      let av = apipe.first();
      let bv = bpipe.first();
      return f(av, bv);
   endmethod
   method Action deq();
      apipe.deq();
      bpipe.deq();
   endmethod
   method Bool notEmpty();
      return apipe.notEmpty() && bpipe.notEmpty();
   endmethod
endmodule

module mkMap#(function b f(a av), PipeOut#(a) apipe)(PipeOut#(b));
   method b first();
      let av = apipe.first();
      return f(av);
   endmethod
   method Action deq();
      apipe.deq();
   endmethod
   method Bool notEmpty();
      return apipe.notEmpty();
   endmethod
endmodule

typedef (function Module #(PipeOut #(tb)) mkPipeOut(PipeOut#(ta) ifc)) MkPipeOut#(type ta, type tb);

typeclass ReducePipe#( numeric type n, type a);
   module [Module] mkReducePipe (MkPipeOut#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(n,a)) inpipe,
				 PipeOut#(a) ifc);
endtypeclass
instance ReducePipe#(1, a);
   module [Module] mkReducePipe (MkPipeOut#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(1,a)) inpipe,
				 PipeOut#(a) ifc);
      let pipe <- mkMap(head, inpipe);
      return pipe;
   endmodule
endinstance
instance ReducePipe#(2, a);
   module [Module] mkReducePipe (MkPipeOut#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(2,a)) inpipe,
				 PipeOut#(a) ifc);
      function Tuple2#(a,a) foo(Vector#(2,a) invec); return tuple2(invec[0], invec[1]); endfunction
      PipeOut#(Tuple2#(a,a)) zippipe <- mkMap(foo, inpipe);
      let pipe <- combinepipe(zippipe);
      return pipe;
   endmodule
endinstance


added mkConnectionWithClocks for GetF/PutF

Change-Id: I29faefef78eb6ae8787b7d7b84660be29a4945c3

// 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 GetPut :: *;
import GetPutF :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;

instance ConnectableWithClocks#(Get#(a), Put#(a)) provisos (Bits#(a, awidth));
   module mkConnectionWithClocks#(Get#(a) in, Put#(a) out,
                                  Clock inClock, Reset inReset,
                                  Clock outClock, Reset outReset)(Empty) provisos (Bits#(a, awidth));
       SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(1, inClock, inReset, outClock);
       rule doGet;
           let v <- in.get();
	   synchronizer.enq(v);
       endrule
       rule doPut;
           let v = synchronizer.first;
	   synchronizer.deq;
	   out.put(v);
       endrule
   endmodule: mkConnectionWithClocks
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(GetF#(a), PutF#(a)) provisos (Bits#(a, awidth));
   module mkConnectionWithClocks#(GetF#(a) in, PutF#(a) out,
                                  Clock inClock, Reset inReset,
                                  Clock outClock, Reset outReset)(Empty) provisos (Bits#(a, awidth));
       SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(1, inClock, inReset, outClock);
       rule doGet;
           let v <- in.get();
	   synchronizer.enq(v);
       endrule
       rule doPut;
           let v = synchronizer.first;
	   synchronizer.deq;
	   out.put(v);
       endrule
   endmodule: mkConnectionWithClocks
endinstance: ConnectableWithClocks

instance ConnectableWithClocks#(GetF#(a), Put#(a)) provisos (Bits#(a, awidth));
   module mkConnectionWithClocks#(GetF#(a) in, Put#(a) out,
                                  Clock inClock, Reset inReset,
                                  Clock outClock, Reset outReset)(Empty) provisos (Bits#(a, awidth));
       SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(1, inClock, inReset, outClock);
       rule doGet;
           let v <- in.get();
	   synchronizer.enq(v);
       endrule
       rule doPut;
           let v = synchronizer.first;
	   synchronizer.deq;
	   out.put(v);
       endrule
   endmodule: mkConnectionWithClocks
endinstance: ConnectableWithClocks

module mkClockBinder#(a ifc) (a);
   return ifc;
endmodule

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

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

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

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

import GetPut :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;

instance ConnectableWithClocks#(Get#(a), Put#(a)) provisos (Bits#(a, awidth));
   module mkConnectionWithClocks#(Get#(a) in, Put#(a) out,
                                  Clock inClock, Reset inReset,
                                  Clock outClock, Reset outReset)(Empty) provisos (Bits#(a, awidth));
       SyncFIFOIfc#(a) synchronizer <- mkSyncFIFO(1, inClock, inReset, outClock);
       rule doGet;
           let v <- in.get();
	   synchronizer.enq(v);
       endrule
       rule doPut;
           let v = synchronizer.first;
	   synchronizer.deq;
	   out.put(v);
       endrule
   endmodule: mkConnectionWithClocks
endinstance: ConnectableWithClocks

module mkClockBinder#(a ifc) (a);
   return ifc;
endmodule


trace writeDone also

trace writeDone also

// Copyright (c) 2016 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 FIFOF::*;
import Pipe::*;
import GetPut::*;
import MemTypes::*;
import ConnectalMemory::*;

module mkTraceReadClient#(PipeIn#(Tuple4#(dmaChanId,Bool,MemRequest,Bit#(timeStampWidth))) tracePipe,
			  PipeIn#(Tuple4#(dmaChanId,Bool,MemData#(dataWidth),Bit#(timeStampWidth))) traceDataPipe,
			  dmaChanId chan,
			  MemReadClient#(dataWidth) m)
   (MemReadClient#(dataWidth));

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

   let reqFifo  <- mkFIFOF();
   let dataFifo <- mkFIFOF();

   rule rl_rd_req;
      let mr <- m.readReq.get();
      if (tracePipe.notFull())
	 tracePipe.enq(tuple4(chan, False, mr, cycles));
      reqFifo.enq(mr);
   endrule

   rule rl_rd_data;
      let md <- toGet(dataFifo).get();
      if (traceDataPipe.notFull())
	 traceDataPipe.enq(tuple4(chan, False, md, cycles));
      m.readData.put(md);
   endrule

   interface Get readReq = toGet(reqFifo);
   interface Put readData = toPut(dataFifo);
endmodule

module mkTraceWriteClient#(PipeIn#(Tuple4#(dmaChanId,Bool,MemRequest,Bit#(timeStampWidth))) tracePipe,
			   PipeIn#(Tuple4#(dmaChanId,Bool,MemData#(dataWidth),Bit#(timeStampWidth))) traceDataPipe,
			   PipeIn#(Tuple2#(dmaChanId,Bit#(timeStampWidth))) traceDonePipe,
			   dmaChanId chan, MemWriteClient#(dataWidth) m)
   (MemWriteClient#(dataWidth));

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

   let reqFifo <- mkFIFOF();
   let dataFifo <- mkFIFOF();
   let doneFifo <- mkFIFOF();

   rule rl_wr_req;
      let mr <- m.writeReq.get();
      if (tracePipe.notFull())
	 tracePipe.enq(tuple4(chan, True, mr, cycles));
      reqFifo.enq(mr);
   endrule

   rule rl_wr_data;
      let md <- m.writeData.get();
      if (traceDataPipe.notFull())
	 traceDataPipe.enq(tuple4(chan, True, md, cycles));
      dataFifo.enq(md);
   endrule

   rule rl_wr_done;
      let tag <- toGet(doneFifo).get();
      if (traceDonePipe.notFull())
	 traceDonePipe.enq(tuple2(chan, cycles));
      m.writeDone.put(tag);
   endrule

   interface Get writeReq = toGet(reqFifo);
   interface Get writeData = toGet(dataFifo);
   interface Put writeDone = toPut(doneFifo);
endmodule

// Copyright (c) 2016 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 FIFOF::*;
import Pipe::*;
import GetPut::*;
import MemTypes::*;
import ConnectalMemory::*;

module mkTraceReadClient#(PipeIn#(Tuple4#(dmaChanId,Bool,MemRequest,Bit#(timeStampWidth))) tracePipe,
			  PipeIn#(Tuple4#(dmaChanId,Bool,MemData#(dataWidth),Bit#(timeStampWidth))) traceDataPipe,
			  dmaChanId chan,
			  MemReadClient#(dataWidth) m)
   (MemReadClient#(dataWidth));

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

   let reqFifo  <- mkFIFOF();
   let dataFifo <- mkFIFOF();

   rule rl_rd_req;
      let mr <- m.readReq.get();
      if (tracePipe.notFull())
	 tracePipe.enq(tuple4(chan, False, mr, cycles));
      reqFifo.enq(mr);
   endrule

   rule rl_rd_data;
      let md <- toGet(dataFifo).get();
      if (traceDataPipe.notFull())
	 traceDataPipe.enq(tuple4(chan, False, md, cycles));
      m.readData.put(md);
   endrule

   interface Get readReq = toGet(reqFifo);
   interface Put readData = toPut(dataFifo);
endmodule

module mkTraceWriteClient#(PipeIn#(Tuple4#(dmaChanId,Bool,MemRequest,Bit#(timeStampWidth))) tracePipe,
			   PipeIn#(Tuple4#(dmaChanId,Bool,MemData#(dataWidth),Bit#(timeStampWidth))) traceDataPipe,
			   dmaChanId chan, MemWriteClient#(dataWidth) m)
   (MemWriteClient#(dataWidth));

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

   let reqFifo <- mkFIFOF();
   let dataFifo <- mkFIFOF();

   rule rl_wr_req;
      let mr <- m.writeReq.get();
      if (tracePipe.notFull())
	 tracePipe.enq(tuple4(chan, True, mr, cycles));
      reqFifo.enq(mr);
   endrule

   rule rl_wr_data;
      let md <- m.writeData.get();
      if (traceDataPipe.notFull())
	 traceDataPipe.enq(tuple4(chan, True, md, cycles));
      dataFifo.enq(md);
   endrule

   interface Get writeReq = toGet(reqFifo);
   interface Get writeData = toGet(dataFifo);
   interface Put writeDone = m.writeDone;
endmodule


fixed typo

fixed typo

// 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.
`include "ConnectalProjectConfig.bsv"
import ConnectalConfig::*;
import FIFO::*;
import GetPut::*;
import ClientServer::*;
import AxiMasterSlave::*;
import Axi4MasterSlave::*;
import MemTypes::*;
import ConnectalMemory::*;

module mkAxiDmaSlave#(PhysMemSlave#(addrWidth,dataWidth) slave) (Axi3Slave#(addrWidth,dataWidth,12));
   let beatShift = fromInteger(valueOf(TLog#(TDiv#(dataWidth,8))));
   interface Put req_ar;
      method Action put((Axi3ReadRequest#(addrWidth, 12)) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.read_server.readReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen,  tag:truncate(req.id)
`ifdef BYTE_ENABLES
						      , firstbe: maxBound, lastbe: maxBound
`endif
						      });
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(dataWidth, 12)) get;
	 let resp <- slave.read_server.readData.get;
	 return Axi3ReadResponse{data:resp.data, resp:0, last:1, id:extend(resp.tag)};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth, 12) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.write_server.writeReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen, tag:truncate(req.id)
`ifdef BYTE_ENABLES
							, firstbe: maxBound, lastbe: maxBound
`endif
							});
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(dataWidth, 12) resp);
	 slave.write_server.writeData.put(MemData{data:resp.data, tag:truncate(resp.id), last: resp.last == 1});
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(12)) get;
	 let rv <- slave.write_server.writeDone.get;
	 return Axi3WriteResponse{resp:0, id:extend(rv)};
      endmethod
   endinterface
endmodule

module mkAxiDmaMaster#(PhysMemMaster#(addrWidth,dataWidth) master) (Axi3Master#(addrWidth,dataWidth,tagWidth))

   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(tagWidth,a__,MemTagSize),
	    Add#(TDiv#(64,8),b__,dataWidthBytes),
	    Bits#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))));

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))) reqs <- mkSizedFIFO(32);
   Reg#(Bit#(dataWidthBytes)) lastbeReg <- mkReg(maxBound);

   let beat_shift = fromInteger(valueOf(beatShift));

   interface Get req_aw;
      method ActionValue#(Axi3WriteRequest#(addrWidth,tagWidth)) get();
	 let req <- master.write_client.writeReq.get;
	 reqs.enq(tuple3(truncate(req.burstLen),reqFirstByteEnable(req),reqLastByteEnable(req)));
	 return Axi3WriteRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Get resp_write;
      method ActionValue#(Axi3WriteData#(dataWidth,tagWidth)) get();
	 let tagdata <- master.write_client.writeData.get();
	 let burstLen = burstReg;
	 Bit#(dataWidthBytes) byteEnable = extend((burstLen == 1) ? lastbeReg : maxBound);
	 if (burstLen == 0) begin
	    match { .bl, .firstbe, .lastbe } = reqs.first;
	    burstLen = bl >> beat_shift;
	    reqs.deq;
`ifdef BYTE_ENABLES
	    byteEnable = extend(firstbe);
	    lastbeReg <= lastbe;
`endif
	 end
	 burstReg <= burstLen-1;
	 Bit#(1) last = burstLen == 1 ? 1'b1 : 1'b0;

	 return Axi3WriteData { data: tagdata.data, byteEnable: byteEnable, last: last, id: truncate(tagdata.tag) };
      endmethod
   endinterface
   interface Put resp_b;
      method Action put(Axi3WriteResponse#(tagWidth) resp);
	 master.write_client.writeDone.put(extend(resp.id));
      endmethod
   endinterface
   interface Get req_ar;
      method ActionValue#(Axi3ReadRequest#(addrWidth,tagWidth)) get();
	 let req <- master.read_client.readReq.get;
	 //$display("req_ar %h", req.tag);
	 return Axi3ReadRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Put resp_read;
      method Action put(Axi3ReadResponse#(dataWidth,tagWidth) response);
	 //$display("resp_read %h %h", response.data, response.id);
	 master.read_client.readData.put(MemData { data: response.data, tag: extend(response.id), last: response.last == 1 });
      endmethod
   endinterface

endmodule

module mkAxi4DmaSlave#(PhysMemSlave#(addrWidth,dataWidth) slave) (Axi4Slave#(addrWidth,dataWidth,12));
   let beatShift = fromInteger(valueOf(TLog#(TDiv#(dataWidth,8))));
   interface Put req_ar;
      method Action put((Axi4ReadRequest#(addrWidth, 12)) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.read_server.readReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen,  tag:truncate(req.id)
`ifdef BYTE_ENABLES
						      , firstbe: maxBound, lastbe: maxBound
`endif
						      });
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi4ReadResponse#(dataWidth, 12)) get;
	 let resp <- slave.read_server.readData.get;
	 return Axi4ReadResponse{data:resp.data, resp:0, last:1, id:extend(resp.tag)};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi4WriteRequest#(addrWidth, 12) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.write_server.writeReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen, tag:truncate(req.id)
`ifdef BYTE_ENABLES
							, firstbe: maxBound, lastbe: maxBound
`endif
							});
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi4WriteData#(dataWidth, 12) resp);
	 slave.write_server.writeData.put(MemData{data:resp.data, tag:truncate(resp.id), last: resp.last == 1});
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi4WriteResponse#(12)) get;
	 let rv <- slave.write_server.writeDone.get;
	 return Axi4WriteResponse{resp:0, id:extend(rv)};
      endmethod
   endinterface
endmodule

module mkAxi4DmaMaster#(PhysMemMaster#(addrWidth,dataWidth) master) (Axi4Master#(addrWidth,dataWidth,tagWidth))

   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(tagWidth,a__,MemTagSize),
	    Add#(TDiv#(64,8),b__,dataWidthBytes),
	    Bits#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))));

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))) reqs <- mkSizedFIFO(32);
   Reg#(Bit#(dataWidthBytes)) lastbeReg <- mkReg(maxBound);

   let beat_shift = fromInteger(valueOf(beatShift));

   interface Get req_aw;
      method ActionValue#(Axi4WriteRequest#(addrWidth,tagWidth)) get();
	 let req <- master.write_client.writeReq.get;
	 reqs.enq(tuple3(truncate(req.burstLen),reqFirstByteEnable(req),reqLastByteEnable(req)));
	 return Axi4WriteRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Get resp_write;
      method ActionValue#(Axi4WriteData#(dataWidth,tagWidth)) get();
	 let tagdata <- master.write_client.writeData.get();
	 let burstLen = burstReg;
	 Bit#(dataWidthBytes) byteEnable = extend((burstLen == 1) ? lastbeReg : maxBound);
	 if (burstLen == 0) begin
	    match { .bl, .firstbe, .lastbe } = reqs.first;
	    burstLen = bl >> beat_shift;
	    reqs.deq;
`ifdef BYTE_ENABLES
	    byteEnable = extend(firstbe);
	    lastbeReg <= lastbe;
`endif
	 end
	 burstReg <= burstLen-1;
	 Bit#(1) last = burstLen == 1 ? 1'b1 : 1'b0;

	 return Axi4WriteData { data: tagdata.data, byteEnable: byteEnable, last: last, id: truncate(tagdata.tag) };
      endmethod
   endinterface
   interface Put resp_b;
      method Action put(Axi4WriteResponse#(tagWidth) resp);
	 master.write_client.writeDone.put(extend(resp.id));
      endmethod
   endinterface
   interface Get req_ar;
      method ActionValue#(Axi4ReadRequest#(addrWidth,tagWidth)) get();
	 let req <- master.read_client.readReq.get;
	 //$display("req_ar %h", req.tag);
	 return Axi4ReadRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Put resp_read;
      method Action put(Axi4ReadResponse#(dataWidth,tagWidth) response);
	 //$display("resp_read %h %h", response.data, response.id);
	 master.read_client.readData.put(MemData { data: response.data, tag: extend(response.id), last: response.last == 1 });
      endmethod
   endinterface

endmodule

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
`include "ConnectalProjectConfig.bsv"
import ConnectalConfig::*;
import FIFO::*;
import GetPut::*;
import ClientServer::*;
import AxiMasterSlave::*;
import Axi4MasterSlave::*;
import MemTypes::*;
import ConnectalMemory::*;

module mkAxiDmaSlave#(PhysMemSlave#(addrWidth,dataWidth) slave) (Axi3Slave#(addrWidth,dataWidth,12));
   let beatShift = fromInteger(valueOf(TLog#(TDiv#(dataWidth,8))));
   interface Put req_ar;
      method Action put((Axi3ReadRequest#(addrWidth, 12)) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.read_server.readReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen,  tag:truncate(req.id)
`ifdef BYTE_ENABLES
						      , firstbe: maxBound, lastbe: maxBound
`endif
						      });
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(dataWidth, 12)) get;
	 let resp <- slave.read_server.readData.get;
	 return Axi3ReadResponse{data:resp.data, resp:0, last:1, id:extend(resp.tag)};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth, 12) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.write_server.writeReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen, tag:truncate(req.id)
`ifdef BYTE_ENABLES
							, firstbe: maxBound, lastbe: maxBound
`endif
							});
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(dataWidth, 12) resp);
	 slave.write_server.writeData.put(MemData{data:resp.data, tag:truncate(resp.id), last: resp.last == 1});
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(12)) get;
	 let rv <- slave.write_server.writeDone.get;
	 return Axi3WriteResponse{resp:0, id:extend(rv)};
      endmethod
   endinterface
endmodule

module mkAxiDmaMaster#(PhysMemMaster#(addrWidth,dataWidth) master) (Axi3Master#(addrWidth,dataWidth,tagWidth))

   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(tagWidth,a__,MemTagSize),
	    Add#(TDiv#(64,8),b__,dataWidthBytes),
	    Bits#Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes)));

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))) reqs <- mkSizedFIFO(32);
   Reg#(Bit#(dataWidthBytes)) lastbeReg <- mkReg(maxBound);

   let beat_shift = fromInteger(valueOf(beatShift));

   interface Get req_aw;
      method ActionValue#(Axi3WriteRequest#(addrWidth,tagWidth)) get();
	 let req <- master.write_client.writeReq.get;
	 reqs.enq(tuple3(truncate(req.burstLen),reqFirstByteEnable(req),reqLastByteEnable(req)));
	 return Axi3WriteRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Get resp_write;
      method ActionValue#(Axi3WriteData#(dataWidth,tagWidth)) get();
	 let tagdata <- master.write_client.writeData.get();
	 let burstLen = burstReg;
	 Bit#(dataWidthBytes) byteEnable = extend((burstLen == 1) ? lastbeReg : maxBound);
	 if (burstLen == 0) begin
	    match { .bl, .firstbe, .lastbe } = reqs.first;
	    burstLen = bl >> beat_shift;
	    reqs.deq;
`ifdef BYTE_ENABLES
	    byteEnable = extend(firstbe);
	    lastbeReg <= lastbe;
`endif
	 end
	 burstReg <= burstLen-1;
	 Bit#(1) last = burstLen == 1 ? 1'b1 : 1'b0;

	 return Axi3WriteData { data: tagdata.data, byteEnable: byteEnable, last: last, id: truncate(tagdata.tag) };
      endmethod
   endinterface
   interface Put resp_b;
      method Action put(Axi3WriteResponse#(tagWidth) resp);
	 master.write_client.writeDone.put(extend(resp.id));
      endmethod
   endinterface
   interface Get req_ar;
      method ActionValue#(Axi3ReadRequest#(addrWidth,tagWidth)) get();
	 let req <- master.read_client.readReq.get;
	 //$display("req_ar %h", req.tag);
	 return Axi3ReadRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Put resp_read;
      method Action put(Axi3ReadResponse#(dataWidth,tagWidth) response);
	 //$display("resp_read %h %h", response.data, response.id);
	 master.read_client.readData.put(MemData { data: response.data, tag: extend(response.id), last: response.last == 1 });
      endmethod
   endinterface

endmodule

module mkAxi4DmaSlave#(PhysMemSlave#(addrWidth,dataWidth) slave) (Axi4Slave#(addrWidth,dataWidth,12));
   let beatShift = fromInteger(valueOf(TLog#(TDiv#(dataWidth,8))));
   interface Put req_ar;
      method Action put((Axi4ReadRequest#(addrWidth, 12)) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.read_server.readReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen,  tag:truncate(req.id)
`ifdef BYTE_ENABLES
						      , firstbe: maxBound, lastbe: maxBound
`endif
						      });
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi4ReadResponse#(dataWidth, 12)) get;
	 let resp <- slave.read_server.readData.get;
	 return Axi4ReadResponse{data:resp.data, resp:0, last:1, id:extend(resp.tag)};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi4WriteRequest#(addrWidth, 12) req);
	 let burstLen = extend(req.len+1) << beatShift;
	 slave.write_server.writeReq.put(PhysMemRequest{addr:req.address, burstLen:burstLen, tag:truncate(req.id)
`ifdef BYTE_ENABLES
							, firstbe: maxBound, lastbe: maxBound
`endif
							});
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi4WriteData#(dataWidth, 12) resp);
	 slave.write_server.writeData.put(MemData{data:resp.data, tag:truncate(resp.id), last: resp.last == 1});
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi4WriteResponse#(12)) get;
	 let rv <- slave.write_server.writeDone.get;
	 return Axi4WriteResponse{resp:0, id:extend(rv)};
      endmethod
   endinterface
endmodule

module mkAxi4DmaMaster#(PhysMemMaster#(addrWidth,dataWidth) master) (Axi4Master#(addrWidth,dataWidth,tagWidth))

   provisos(Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift),
	    Add#(tagWidth,a__,MemTagSize),
	    Add#(TDiv#(64,8),b__,dataWidthBytes),
	    Bits#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))));

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Tuple3#(Bit#(8),Bit#(ByteEnableSize),Bit#(dataWidthBytes))) reqs <- mkSizedFIFO(32);
   Reg#(Bit#(dataWidthBytes)) lastbeReg <- mkReg(maxBound);

   let beat_shift = fromInteger(valueOf(beatShift));

   interface Get req_aw;
      method ActionValue#(Axi4WriteRequest#(addrWidth,tagWidth)) get();
	 let req <- master.write_client.writeReq.get;
	 reqs.enq(tuple3(truncate(req.burstLen),reqFirstByteEnable(req),reqLastByteEnable(req)));
	 return Axi4WriteRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Get resp_write;
      method ActionValue#(Axi4WriteData#(dataWidth,tagWidth)) get();
	 let tagdata <- master.write_client.writeData.get();
	 let burstLen = burstReg;
	 Bit#(dataWidthBytes) byteEnable = extend((burstLen == 1) ? lastbeReg : maxBound);
	 if (burstLen == 0) begin
	    match { .bl, .firstbe, .lastbe } = reqs.first;
	    burstLen = bl >> beat_shift;
	    reqs.deq;
`ifdef BYTE_ENABLES
	    byteEnable = extend(firstbe);
	    lastbeReg <= lastbe;
`endif
	 end
	 burstReg <= burstLen-1;
	 Bit#(1) last = burstLen == 1 ? 1'b1 : 1'b0;

	 return Axi4WriteData { data: tagdata.data, byteEnable: byteEnable, last: last, id: truncate(tagdata.tag) };
      endmethod
   endinterface
   interface Put resp_b;
      method Action put(Axi4WriteResponse#(tagWidth) resp);
	 master.write_client.writeDone.put(extend(resp.id));
      endmethod
   endinterface
   interface Get req_ar;
      method ActionValue#(Axi4ReadRequest#(addrWidth,tagWidth)) get();
	 let req <- master.read_client.readReq.get;
	 //$display("req_ar %h", req.tag);
	 return Axi4ReadRequest{address:req.addr, len:truncate((req.burstLen>>beat_shift)-1), id:truncate(req.tag), size: axiBusSize(valueOf(dataWidth)), burst: 1, prot: 0, cache: 3, lock:0, qos:0};
      endmethod
   endinterface
   interface Put resp_read;
      method Action put(Axi4ReadResponse#(dataWidth,tagWidth) response);
	 //$display("resp_read %h %h", response.data, response.id);
	 master.read_client.readData.put(MemData { data: response.data, tag: extend(response.id), last: response.last == 1 });
      endmethod
   endinterface

endmodule


remove setCoeff

remove setCoeff

// 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 DDS::*;
import FixedPoint::*;
import Complex::*;
import Pipe::*;
import DDSTestInterfaces::*;

module mkDDSTestRequest#(DDSTestIndication indication) (DDSTestRequest);
   DDS dds <- mkDDS();

   method Action setPhaseAdvance(Bit#(32) i, Bit#(32) f);
    dds.setPhaseAdvance(PhaseType{i: truncate(i), f: truncate(f)});
      indication.setConfigResp();
   endmethod

   method Action getData();
      PhaseType p = dds.getPhase();
      DDSOutType d = dds.osc.first();
      indication.ddsData(zeroExtend(p.i), zeroExtend(pack(d.re)), zeroExtend(pack(d.im)));
   endmethod
endmodule

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

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

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

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

import DDS::*;
import FixedPoint::*;
import Complex::*;
import Pipe::*;
import DDSTestInterfaces::*;

module mkDDSTestRequest#(DDSTestIndication indication) (DDSTestRequest);
   DDS dds <- mkDDS();

   method Action setCoeff(Bit#(11) addr, Bit#(32) valueRe, Bit#(32) valueIm);
    FixedPoint#(2, 23) re = unpack(pack(truncate(valueRe)));
    FixedPoint#(2, 23) im = unpack(pack(truncate(valueIm)));
      cs.setCoeff(addr, Complex{rel: re, img:im});
      indication.setConfigResp();
   endmethod

   method Action setPhaseAdvance(Bit#(32) i, Bit#(32) f);
    dds.setPhaseAdvance(PhaseType{i: truncate(i), f: truncate(f)});
      indication.setConfigResp();
   endmethod

   method Action getData();
      PhaseType p = dds.getPhase();
      DDSOutType d = dds.osc.first();
      indication.ddsData(zeroExtend(p.i), zeroExtend(pack(d.re)), zeroExtend(pack(d.im)));
   endmethod
endmodule


use bram_based mimo for writeDataMimo now that it has 128 entries

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

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

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

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

import FIFO         :: *;
import FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import MIFO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;
import Probe        :: *;
import ConfigCounter ::*;

typedef struct {
   TLPData#(16) tlp;
   TLPLength    dwCount;
   Bool         is3dw;
   Bool         isHeaderOnly;
   } TlpWriteHeaderInfo deriving (Bits);

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

`ifdef XILINX
   `define AXI
`elsif BSIM
   `define AXI
`elsif ALTERA
   `define AVALON
`endif

module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8),
	     Add#(1, a__, busWidthWords),
	     Add#(busWidthWords, b__, 4),
	     Add#(c__, busWidthWords, 128)
      );

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFO#(TlpWriteHeaderInfo) tlpWriteHeaderFifo <- mkFIFO;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
   MIFO#(4,busWidthWords,16,Bit#(32)) completionMimo <- mkMIFO();
   MIFO#(4,busWidthWords,16,TLPTag) completionTagMimo <- mkMIFO();

   mimoCfg.bram_based = True;
    MIMO#(busWidthWords,4,128,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    ConfigCounter#(8) writeDataCnt <- mkConfigCounter(0);
    Reg#(Bit#(10)) writeBurstCount <- mkReg(0);
   FIFO#(Bit#(10)) writeBurstCountFifo <- mkFIFO();
    Reg#(TLPLength)  writeDwCount <- mkReg(0); // how many 4 byte (double) words to send
    Reg#(LUInt#(4))    tlpDwCount <- mkReg(0); // how many to send in the next tlp (at most 4)
    Reg#(Bool)            lastTlp <- mkReg(False); // if the next tlp sent is the last one
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    Reg#(Bool) quadAlignedTlpHandled <- mkReg(True);

   Wire#(Bool) writeHeaderTlpWire <- mkDWire(False);
   Probe#(Bool) writeHeaderAvailableProbe <- mkProbe;
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);
   Probe#(Bool) writeDataMimoEnqProbe <- mkProbe;
   let    writeDataMimoCountProbe <- mkProbe;
   let writeDataMimoEnqReadyProbe <- mkProbe;
   Probe#(Bool) writeInProgressProbe <- mkProbe;
   Probe#(Bit#(10)) writeBurstCountProbe <- mkProbe;
   rule updateProbe0;
      writeDataMimoCountProbe    <= writeDataMimo.count();
      writeDataMimoEnqReadyProbe <= writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords)));
   endrule
   rule updateProbe2;
      writeHeaderAvailableProbe <= writeHeaderTlpWire;
      writeDataMimoEnqProbe <= writeDataMimoEnqWire;
   endrule

   Reg#(Bool) writeDataCntAboveThreshold <- mkReg(False);
   rule updateWriteDataCntAboveThreshold;
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));
   endrule
   (* descending_urgency = "writeHeaderTlp,updateWriteDataCntAboveThreshold" *)
   rule writeHeaderTlp if (!writeInProgress && writeDataCntAboveThreshold);
      // update for next cycle
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));

      writeHeaderTlpWire <= True;
      let info <- toGet(tlpWriteHeaderFifo).get();
      let tlp     = info.tlp;
      let dwCount = info.dwCount;
      let is3dw   = info.is3dw;
      let isHeaderOnly = info.isHeaderOnly;

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      if (is3dw) begin
	 if (hdr_3dw.format != MEM_WRITE_3DW_DATA)
	    $display("MemSlaveEngine: expecting MEM_WRITE_3DW_DATA, got %d", hdr_3dw.format);
	 Vector#(4, Bit#(32)) v = unpack(0);
         tlp.sof = True;
`ifdef AXI
         v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
         tlp.eof = (dwCount == 1) ? True : False;
         dwCount = dwCount - 1;
         writeDataCnt.decrement(1);
`elsif AVALON
         let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
         // if quad-word aligned, insert bubble.
         if (!quadWordAligned) begin
            v = writeDataMimo.first();
            writeDataMimo.deq(1);
            hdr_3dw.data = v[0];
         end
         else begin
            hdr_3dw.data = unpack(0);
         end
         tlp.eof = (dwCount == 1 && !quadWordAligned) ? True : False;
         if (!quadWordAligned) begin
            dwCount = dwCount - 1;
            writeDataCnt.decrement(1);
         end
`endif
	 tlp.be = 16'hffff;
	 tlp.data = pack(hdr_3dw);
      end
      else begin
         quadAlignedTlpHandled <= isQuadWordAligned(getLowerAddr(truncate(unpack(hdr_4dw.addr)), hdr_4dw.firstbe));
	 tlp.be = 16'hffff;
      end

      tlpOutFifo.enq(tlp);
      $display("writeHeaderTlp dwCount=%d", dwCount);
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      writeInProgress <= (dwCount != 0);
      writeInProgressProbe <= (dwCount != 0);
      if (isHeaderOnly) begin
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
      end

   endrule

   rule writeTlps if (writeInProgress); // already verified  writeDataMimo.deqReadyN(tlpDwCount)) for this transaction
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);
      Integer currDwCount = 4;

`ifdef AVALON
      if (!quadAlignedTlpHandled) begin
         currDwCount = 3; // 3 Data Dwords in this cycle.
         quadAlignedTlpHandled <= True;
      end
`endif

      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      writeDataMimo.deq(tlpDwCount);
      v = writeDataMimo.first();
      let dwCount = writeDwCount - extend(pack(tlpDwCount));
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(fromInteger(currDwCount),unpack(dwCount)));
      writeDataCnt.decrement(unpack(extend(pack(tlpDwCount))));
      lastTlp <= (dwCount <= 4);
      if (tlpDwCount == 4)
	 tlp.be = 16'hffff;
      else if (tlpDwCount == 3)
	 tlp.be = 16'hfff0;
      else if (tlpDwCount == 2)
	 tlp.be = 16'hff00;
      else if (tlpDwCount == 1)
	 tlp.be = 16'hf000;
      tlp.eof = lastTlp;
      if (lastTlp) begin
	 writeInProgress <= False;
	 writeInProgressProbe <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 $display("writeDwCount=%d will be zero", writeDwCount);
      end

      for (Integer i = 0; i < currDwCount; i = i + 1) begin
	 tlp.data[(i+1)*32-1:i*32] = v[(currDwCount-1)-i];
      end

      tlpOutFifo.enq(tlp);
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   FIFOF#(TLPData#(16)) tlpDecodeFifo <- mkFIFOF();
   Reg#(TLPLength) wordCountReg <- mkReg(0);
   rule tlpInRule;
      let tlp <- toGet(tlpInFifo).get();
      tlpDecodeFifo.enq(tlp);
   endrule

   rule handleTlpRule;
      let tlp = tlpDecodeFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);
      let wordCount = wordCountReg;
`ifdef AXI
      let dataInSecondTlp = False;
`elsif AVALON
      let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
      let dataInSecondTlp = quadWordAligned;
`endif
      if (!tlp.sof) begin
	 vec = reverse(tlpvec);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReady()
	    && completionTagMimo.enqReady())
	    begin
	       UInt#(3) count = 4;
	       if (tlp.eof) begin
		  count = truncate(unpack(wordCountReg));
	       end
	       wordCount = wordCountReg - extend(pack(count));
	       completionMimo.enq(count, vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(count, tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReady()
	       && completionTagMimo.enqReady()) begin
            TLPTag tag = hdr_completion.tag;
            lastTag <= tag;
            if (!dataInSecondTlp) begin
               vec[0] = hdr_3dw.data;
               wordCount = hdr_3dw.length - 1;
               completionMimo.enq(1, vec);
               completionTagMimo.enq(1, replicate(tag));
            end
	    handled = True;
      end
      wordCountReg <= wordCount;
      $display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled) begin
	 tlpDecodeFifo.deq();
      end
   endrule

   FIFO#(PhysMemRequest#(40)) readReqFifo <- mkFIFO();
   rule readReqRule if (!writeInProgress && !writeDataMimo.deqReady());
      let req <- toGet(readReqFifo).get();
      let burstLen = req.burstLen >> beat_shift;
      let addr = req.addr;
      let arid = req.tag;

      TLPData#(16) tlp = defaultValue;
      tlp.sof = True;
      tlp.eof = True;
      tlp.hit = 7'h00;
      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
      if (addr[39:32] != 0) begin
	 TLPMemory4DWHeader hdr_4dw = defaultValue;
	 hdr_4dw.format = MEM_READ_4DW_NO_DATA;
	 hdr_4dw.tag = extend(arid);
	 hdr_4dw.reqid = my_id;
	 hdr_4dw.nosnoop = SNOOPING_REQD;
	 hdr_4dw.addr = addr[40-1:2];
	 hdr_4dw.length = tlplen;
	 hdr_4dw.firstbe = 4'hf;
	 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_4dw);
	 tlp.be = 16'hffff;
      end
      else begin
	 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	 hdr_3dw.format = MEM_READ_3DW_NO_DATA;
	 hdr_3dw.tag = extend(arid);
	 hdr_3dw.reqid = my_id;
	 hdr_3dw.nosnoop = SNOOPING_REQD;
	 hdr_3dw.addr = addr[32-1:2];
	 hdr_3dw.length = tlplen;
	 hdr_3dw.firstbe = 4'hf;
	 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_3dw);
	 tlp.be = 16'hfff0;
      end
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface PhysMemSlave slave;
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(40) req); // if (writeBurstCount == 0);
	    let burstLen = req.burstLen >> beat_shift;
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;

	    TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
	    TLPData#(16) tlp = defaultValue;
	    tlp.sof = True;
	    tlp.eof = False;
	    tlp.hit = 7'h00;
	    tlp.be = 16'hffff;

	    $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	    if ((addr >> 32) != 0) begin
	       TLPMemory4DWHeader hdr_4dw = defaultValue;
	       hdr_4dw.format = MEM_WRITE_4DW_DATA;
	       hdr_4dw.tag = extend(awid);
	       hdr_4dw.reqid = my_id;
	       hdr_4dw.nosnoop = SNOOPING_REQD;
	       hdr_4dw.addr = addr[40-1:2];
	       hdr_4dw.length = tlplen;
	       hdr_4dw.firstbe = 4'hf;
	       hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	       tlp.data = pack(hdr_4dw);
	    end
	    else begin
	       writeIs3dw = True;
	       TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	       hdr_3dw.format = MEM_WRITE_3DW_DATA;
	       hdr_3dw.tag = extend(awid);
	       hdr_3dw.reqid = my_id;
	       hdr_3dw.nosnoop = SNOOPING_REQD;
	       hdr_3dw.addr = addr[32-1:2];
	       hdr_3dw.length = tlplen;
	       hdr_3dw.firstbe = 4'hf;
	       hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

	       tlp.be = 16'hfff0; // no data word in this TLP

	       tlp.data = pack(hdr_3dw);
	    end
	    tlpWriteHeaderFifo.enq(TlpWriteHeaderInfo {tlp: tlp, dwCount: tlplen, is3dw: writeIs3dw, isHeaderOnly: (writeIs3dw && tlplen == 1) });
	    writeBurstCountFifo.enq(extend(burstLen));
	    writeTag.enq(extend(awid));
         endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	    let burstLen = writeBurstCount;
	    if (burstLen == 0) begin
	       burstLen <- toGet(writeBurstCountFifo).get();
	    end
	    writeBurstCount <= extend(burstLen-1);
	    writeBurstCountProbe <= extend(burstLen-1);

	    Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	    writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
            writeDataCnt.increment(fromInteger(valueOf(busWidthWords)));
	    writeDataMimoEnqWire <= True;
         endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(40) req);
	    readReqFifo.enq(req);
         endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReady()
							   && completionTagMimo.deqReady());
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
              for (Integer i = 0; i < valueOf(busWidthWords); i = i+1) begin
`ifdef AXI
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
`elsif AVALON
		 v[(i+1)*32-1:i*32] = data_v[i];
`endif
              end
	      return MemData { data: v, tag: truncate(tag_v[0]), last: True};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine

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

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

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

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

import FIFO         :: *;
import FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import MIFO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;
import Probe        :: *;
import ConfigCounter ::*;

typedef struct {
   TLPData#(16) tlp;
   TLPLength    dwCount;
   Bool         is3dw;
   Bool         isHeaderOnly;
   } TlpWriteHeaderInfo deriving (Bits);

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

`ifdef XILINX
   `define AXI
`elsif BSIM
   `define AXI
`elsif ALTERA
   `define AVALON
`endif

module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8),
	     Add#(1, a__, busWidthWords),
	     Add#(busWidthWords, b__, 4),
	     Add#(c__, busWidthWords, 128)
      );

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFO#(TlpWriteHeaderInfo) tlpWriteHeaderFifo <- mkFIFO;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
   MIFO#(4,busWidthWords,16,Bit#(32)) completionMimo <- mkMIFO();
   MIFO#(4,busWidthWords,16,TLPTag) completionTagMimo <- mkMIFO();

    MIMO#(busWidthWords,4,128,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    ConfigCounter#(8) writeDataCnt <- mkConfigCounter(0);
    Reg#(Bit#(10)) writeBurstCount <- mkReg(0);
   FIFO#(Bit#(10)) writeBurstCountFifo <- mkFIFO();
    Reg#(TLPLength)  writeDwCount <- mkReg(0); // how many 4 byte (double) words to send
    Reg#(LUInt#(4))    tlpDwCount <- mkReg(0); // how many to send in the next tlp (at most 4)
    Reg#(Bool)            lastTlp <- mkReg(False); // if the next tlp sent is the last one
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    Reg#(Bool) quadAlignedTlpHandled <- mkReg(True);

   Wire#(Bool) writeHeaderTlpWire <- mkDWire(False);
   Probe#(Bool) writeHeaderAvailableProbe <- mkProbe;
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);
   Probe#(Bool) writeDataMimoEnqProbe <- mkProbe;
   let    writeDataMimoCountProbe <- mkProbe;
   let writeDataMimoEnqReadyProbe <- mkProbe;
   Probe#(Bool) writeInProgressProbe <- mkProbe;
   Probe#(Bit#(10)) writeBurstCountProbe <- mkProbe;
   rule updateProbe0;
      writeDataMimoCountProbe    <= writeDataMimo.count();
      writeDataMimoEnqReadyProbe <= writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords)));
   endrule
   rule updateProbe2;
      writeHeaderAvailableProbe <= writeHeaderTlpWire;
      writeDataMimoEnqProbe <= writeDataMimoEnqWire;
   endrule

   Reg#(Bool) writeDataCntAboveThreshold <- mkReg(False);
   rule updateWriteDataCntAboveThreshold;
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));
   endrule
   (* descending_urgency = "writeHeaderTlp,updateWriteDataCntAboveThreshold" *)
   rule writeHeaderTlp if (!writeInProgress && writeDataCntAboveThreshold);
      // update for next cycle
      writeDataCntAboveThreshold <= (writeDataCnt.read >= truncate(unpack(tlpWriteHeaderFifo.first.dwCount)));

      writeHeaderTlpWire <= True;
      let info <- toGet(tlpWriteHeaderFifo).get();
      let tlp     = info.tlp;
      let dwCount = info.dwCount;
      let is3dw   = info.is3dw;
      let isHeaderOnly = info.isHeaderOnly;

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      if (is3dw) begin
	 if (hdr_3dw.format != MEM_WRITE_3DW_DATA)
	    $display("MemSlaveEngine: expecting MEM_WRITE_3DW_DATA, got %d", hdr_3dw.format);
	 Vector#(4, Bit#(32)) v = unpack(0);
         tlp.sof = True;
`ifdef AXI
         v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
         tlp.eof = (dwCount == 1) ? True : False;
         dwCount = dwCount - 1;
         writeDataCnt.decrement(1);
`elsif AVALON
         let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
         // if quad-word aligned, insert bubble.
         if (!quadWordAligned) begin
            v = writeDataMimo.first();
            writeDataMimo.deq(1);
            hdr_3dw.data = v[0];
         end
         else begin
            hdr_3dw.data = unpack(0);
         end
         tlp.eof = (dwCount == 1 && !quadWordAligned) ? True : False;
         if (!quadWordAligned) begin
            dwCount = dwCount - 1;
            writeDataCnt.decrement(1);
         end
`endif
	 tlp.be = 16'hffff;
	 tlp.data = pack(hdr_3dw);
      end
      else begin
         quadAlignedTlpHandled <= isQuadWordAligned(getLowerAddr(truncate(unpack(hdr_4dw.addr)), hdr_4dw.firstbe));
	 tlp.be = 16'hffff;
      end

      tlpOutFifo.enq(tlp);
      $display("writeHeaderTlp dwCount=%d", dwCount);
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      writeInProgress <= (dwCount != 0);
      writeInProgressProbe <= (dwCount != 0);
      if (isHeaderOnly) begin
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
      end

   endrule

   rule writeTlps if (writeInProgress); // already verified  writeDataMimo.deqReadyN(tlpDwCount)) for this transaction
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);
      Integer currDwCount = 4;

`ifdef AVALON
      if (!quadAlignedTlpHandled) begin
         currDwCount = 3; // 3 Data Dwords in this cycle.
         quadAlignedTlpHandled <= True;
      end
`endif

      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      writeDataMimo.deq(tlpDwCount);
      v = writeDataMimo.first();
      let dwCount = writeDwCount - extend(pack(tlpDwCount));
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(fromInteger(currDwCount),unpack(dwCount)));
      writeDataCnt.decrement(unpack(extend(pack(tlpDwCount))));
      lastTlp <= (dwCount <= 4);
      if (tlpDwCount == 4)
	 tlp.be = 16'hffff;
      else if (tlpDwCount == 3)
	 tlp.be = 16'hfff0;
      else if (tlpDwCount == 2)
	 tlp.be = 16'hff00;
      else if (tlpDwCount == 1)
	 tlp.be = 16'hf000;
      tlp.eof = lastTlp;
      if (lastTlp) begin
	 writeInProgress <= False;
	 writeInProgressProbe <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 $display("writeDwCount=%d will be zero", writeDwCount);
      end

      for (Integer i = 0; i < currDwCount; i = i + 1) begin
	 tlp.data[(i+1)*32-1:i*32] = v[(currDwCount-1)-i];
      end

      tlpOutFifo.enq(tlp);
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   FIFOF#(TLPData#(16)) tlpDecodeFifo <- mkFIFOF();
   Reg#(TLPLength) wordCountReg <- mkReg(0);
   rule tlpInRule;
      let tlp <- toGet(tlpInFifo).get();
      tlpDecodeFifo.enq(tlp);
   endrule

   rule handleTlpRule;
      let tlp = tlpDecodeFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);
      let wordCount = wordCountReg;
`ifdef AXI
      let dataInSecondTlp = False;
`elsif AVALON
      let quadWordAligned = isQuadWordAligned(getLowerAddr(hdr_3dw.addr, hdr_3dw.firstbe));
      let dataInSecondTlp = quadWordAligned;
`endif
      if (!tlp.sof) begin
	 vec = reverse(tlpvec);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReady()
	    && completionTagMimo.enqReady())
	    begin
	       UInt#(3) count = 4;
	       if (tlp.eof) begin
		  count = truncate(unpack(wordCountReg));
	       end
	       wordCount = wordCountReg - extend(pack(count));
	       completionMimo.enq(count, vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(count, tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReady()
	       && completionTagMimo.enqReady()) begin
            TLPTag tag = hdr_completion.tag;
            lastTag <= tag;
            if (!dataInSecondTlp) begin
               vec[0] = hdr_3dw.data;
               wordCount = hdr_3dw.length - 1;
               completionMimo.enq(1, vec);
               completionTagMimo.enq(1, replicate(tag));
            end
	    handled = True;
      end
      wordCountReg <= wordCount;
      $display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled) begin
	 tlpDecodeFifo.deq();
      end
   endrule

   FIFO#(PhysMemRequest#(40)) readReqFifo <- mkFIFO();
   rule readReqRule if (!writeInProgress && !writeDataMimo.deqReady());
      let req <- toGet(readReqFifo).get();
      let burstLen = req.burstLen >> beat_shift;
      let addr = req.addr;
      let arid = req.tag;

      TLPData#(16) tlp = defaultValue;
      tlp.sof = True;
      tlp.eof = True;
      tlp.hit = 7'h00;
      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
      if (addr[39:32] != 0) begin
	 TLPMemory4DWHeader hdr_4dw = defaultValue;
	 hdr_4dw.format = MEM_READ_4DW_NO_DATA;
	 hdr_4dw.tag = extend(arid);
	 hdr_4dw.reqid = my_id;
	 hdr_4dw.nosnoop = SNOOPING_REQD;
	 hdr_4dw.addr = addr[40-1:2];
	 hdr_4dw.length = tlplen;
	 hdr_4dw.firstbe = 4'hf;
	 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_4dw);
	 tlp.be = 16'hffff;
      end
      else begin
	 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	 hdr_3dw.format = MEM_READ_3DW_NO_DATA;
	 hdr_3dw.tag = extend(arid);
	 hdr_3dw.reqid = my_id;
	 hdr_3dw.nosnoop = SNOOPING_REQD;
	 hdr_3dw.addr = addr[32-1:2];
	 hdr_3dw.length = tlplen;
	 hdr_3dw.firstbe = 4'hf;
	 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_3dw);
	 tlp.be = 16'hfff0;
      end
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface PhysMemSlave slave;
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(40) req); // if (writeBurstCount == 0);
	    let burstLen = req.burstLen >> beat_shift;
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;

	    TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
	    TLPData#(16) tlp = defaultValue;
	    tlp.sof = True;
	    tlp.eof = False;
	    tlp.hit = 7'h00;
	    tlp.be = 16'hffff;

	    $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	    if ((addr >> 32) != 0) begin
	       TLPMemory4DWHeader hdr_4dw = defaultValue;
	       hdr_4dw.format = MEM_WRITE_4DW_DATA;
	       hdr_4dw.tag = extend(awid);
	       hdr_4dw.reqid = my_id;
	       hdr_4dw.nosnoop = SNOOPING_REQD;
	       hdr_4dw.addr = addr[40-1:2];
	       hdr_4dw.length = tlplen;
	       hdr_4dw.firstbe = 4'hf;
	       hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	       tlp.data = pack(hdr_4dw);
	    end
	    else begin
	       writeIs3dw = True;
	       TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	       hdr_3dw.format = MEM_WRITE_3DW_DATA;
	       hdr_3dw.tag = extend(awid);
	       hdr_3dw.reqid = my_id;
	       hdr_3dw.nosnoop = SNOOPING_REQD;
	       hdr_3dw.addr = addr[32-1:2];
	       hdr_3dw.length = tlplen;
	       hdr_3dw.firstbe = 4'hf;
	       hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

	       tlp.be = 16'hfff0; // no data word in this TLP

	       tlp.data = pack(hdr_3dw);
	    end
	    tlpWriteHeaderFifo.enq(TlpWriteHeaderInfo {tlp: tlp, dwCount: tlplen, is3dw: writeIs3dw, isHeaderOnly: (writeIs3dw && tlplen == 1) });
	    writeBurstCountFifo.enq(extend(burstLen));
	    writeTag.enq(extend(awid));
         endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	    let burstLen = writeBurstCount;
	    if (burstLen == 0) begin
	       burstLen <- toGet(writeBurstCountFifo).get();
	    end
	    writeBurstCount <= extend(burstLen-1);
	    writeBurstCountProbe <= extend(burstLen-1);

	    Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	    writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
            writeDataCnt.increment(fromInteger(valueOf(busWidthWords)));
	    writeDataMimoEnqWire <= True;
         endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(40) req);
	    readReqFifo.enq(req);
         endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReady()
							   && completionTagMimo.deqReady());
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
              for (Integer i = 0; i < valueOf(busWidthWords); i = i+1) begin
`ifdef AXI
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
`elsif AVALON
		 v[(i+1)*32-1:i*32] = data_v[i];
`endif
              end
	      return MemData { data: v, tag: truncate(tag_v[0]), last: True};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine


use fromInteger instead of truncate

use fromInteger instead of truncate

// 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 Connectable::*;
import SerialFIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import Arbiter::*;

typedef struct {
   Vector#(2, Bit#(4)) address;
   Bit#(32) payload;
   } DataMessage deriving(Bits);

interface NocNode#(numeric type dim);
   interface PipeIn#(DataMessage) hosttonode;
   interface PipeOut#(DataMessage) nodetohost;
   interface Vector#(dim, PipeIn#(Bit#(1))) linkupin;
   interface Vector#(dim, PipeOut#(Bit#(1))) linkupout;
   interface Vector#(dim, PipeIn#(Bit#(1))) linkdownin;
   interface Vector#(dim, PipeOut#(Bit#(1))) linkdownout;
endinterface

function PipeOut#(Bit#(1)) selectoutput(SerialFIFOTX#(DataMessage) x);
   return x.out;
endfunction

function PipeIn#(Bit#(1)) selectinput(SerialFIFORX#(DataMessage) x);
   return x.in;
endfunction

function Action move(PipeOut#(DataMessage) from, PipeIn#(DataMessage) to);
   return action
	     $display("move %x", from.first);
	     to.enq(from.first);
	     from.deq();
	  endaction;
endfunction

module mkNocArbitrate#(Vector#(n, Bit#(4)) id, Bit#(4) outlink, Vector#(r, PipeOut#(a)) in, PipeIn#(a) out)(Empty)
/*   provisos(
      Add#(0,n,2),
      Add#(0,r,5)
      ) */ ;
   Arbiter_IFC#(r) arb <- mkArbiter(False);
   for (Integer i = 0; i < valueOf(r); i = i + 1)
      rule send_request (out.notFull && in[i].notEmpty);
	 arb.clients[i].request();
      endrule

   rule move;
      if (out.notFull && in[arb.grant_id].notEmpty)
	 action
	    $display("arb id [%d,%d] link %d from %d", id[0], id[1], outlink, arb.grant_id);
	    out.enq(in[arb.grant_id].first());
	    in[arb.grant_id].deq();
	 endaction
   endrule
endmodule

module mkDistributor#(Vector#(n, Bit#(4)) id, PipeOut#(DataMessage) in, Vector#(r, PipeIn#(DataMessage)) out)(Empty)
/*    provisos(
      Add#(0,n,2),
      Add#(0,r,5)
      ) */
;
   rule move;
      $display("distrib [%d,%d] to [%d,%d] v %x",
	 id[0], id[1], in.first.address[0], in.first.address[1],
	 in.first.payload);
      if (in.first.address[0] < id[0])
	 begin
	    $display(" to link 1");
	    move(in, out[1]);
	 end
      else if (in.first.address[0] > id[0])
	 begin
	    $display(" to link 0");
	    move(in, out[0]);
	 end
      else /* in.first.address[0] == id[0] */
	 begin
	    if (in.first.address[1] < id[1])
	       begin
		  $display(" to link 3");
		  move (in, out[3]);
	       end
	    else if (in.first.address[1] > id[1])
	       begin
		  $display(" to link 2");
		  move (in, out[2]);
	       end
	    else
	       begin
		  $display(" to link 4");
		  move(in, out[4]);
	       end
	 end
   endrule
endmodule

// This makes a FIFO which throws away data and is never ready to read
module mkDiscard(FIFOF#(DataMessage));
   method Action enq(DataMessage d);
   endmethod
   method Bool notFull;
      return True;
   endmethod
   method DataMessage first() = ?;
   method Bool notEmpty();
      return False;
   endmethod
   method Action deq;
      if (False) noAction;
   endmethod
   method Action clear = ?;
endmodule

typedef 2 NumDims;
(* synthesize *)
module mkNocNode#(Vector#(NumDims, Bit#(4)) id)(NocNode#(NumDims));
   Integer radix = (valueOf(NumDims) * 2) + 1;

   // host Links
   FIFOF#(DataMessage) fifofromhost <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) fifotohost <- mkSizedFIFOF(4);
   PipeIn#(DataMessage) tohost = toPipeIn(fifotohost);
   PipeOut#(DataMessage) fromhost = toPipeOut(fifofromhost);

   Vector#(NumDims, SerialFIFOTX#(DataMessage)) txup <- replicateM(mkSerialFIFOTX);
   Vector#(NumDims, SerialFIFORX#(DataMessage)) rxup <- replicateM(mkSerialFIFORX);
   Vector#(NumDims, SerialFIFOTX#(DataMessage)) txdown <- replicateM(mkSerialFIFOTX);
   Vector#(NumDims, SerialFIFORX#(DataMessage)) rxdown <- replicateM(mkSerialFIFORX);

   // sources
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeOut#(DataMessage)) switchin = newVector;
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeIn#(DataMessage)) switchout = newVector;
   // buffers for crossbar switch
   Vector#(TAdd#(TMul#(NumDims, 2), 1), Vector#(TAdd#(TMul#(NumDims, 2), 1), FIFOF#(DataMessage))) xp = replicate(newVector);
   // temps for building switch
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeIn#(DataMessage)) tmpin = newVector;
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeOut#(DataMessage)) tmpout = newVector;

   for (Integer i = 0; i < valueOf(NumDims); i = i + 1)
      begin
	 switchin[(2*i) + 0] = rxup[i].out;
	 switchin[(2*i) + 1] = rxdown[i].out;
	 switchout[(2*i) + 0] = txup[i].in;
	 switchout[(2*i) + 1] = txdown[i].in;
      end
   switchin[radix - 1] = fromhost;
   switchout[radix - 1] = tohost;

   for (Integer x = 0; x < radix; x = x + 1)
      for (Integer y = 0; y < radix; y = y + 1)
	 if (x != y) xp[x][y] <- mkSizedFIFOF(4);

   for (Integer x = 0; x < (radix - 1); x = x + 1)
      xp[x][x] <- mkDiscard();

   xp[radix - 1][radix - 1] <- mkSizedFIFOF(4);

   // create distributors

   for (Integer x = 0; x < radix; x = x + 1)
      begin
	 for (Integer y = 0; y < radix; y = y + 1)
	    tmpin[y] = toPipeIn(xp[x][y]);
	 mkDistributor(id, switchin[x], tmpin);
      end
   // create arbiters
   for (Integer y = 0; y < radix; y = y + 1)
      begin
	 for (Integer x = 0; x < radix; x = x + 1)
	    tmpout[x] = toPipeOut(xp[x][y]);
	 mkNocArbitrate(id, fromInteger(y), tmpout, switchout[y]);
      end

  // interface wiring

   interface PipeIn hosttonode = toPipeIn(fifofromhost);
   interface PipeOut nodetohost = toPipeOut(fifotohost);
   interface Vector linkupin = map(selectinput, rxup);
   interface Vector linkupout = map(selectoutput, txup);
   interface Vector linkdownin = map(selectinput, rxdown);
   interface Vector linkdownout = map(selectoutput, txdown);

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 Connectable::*;
import SerialFIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import Arbiter::*;

typedef struct {
   Vector#(2, Bit#(4)) address;
   Bit#(32) payload;
   } DataMessage deriving(Bits);

interface NocNode#(numeric type dim);
   interface PipeIn#(DataMessage) hosttonode;
   interface PipeOut#(DataMessage) nodetohost;
   interface Vector#(dim, PipeIn#(Bit#(1))) linkupin;
   interface Vector#(dim, PipeOut#(Bit#(1))) linkupout;
   interface Vector#(dim, PipeIn#(Bit#(1))) linkdownin;
   interface Vector#(dim, PipeOut#(Bit#(1))) linkdownout;
endinterface

function PipeOut#(Bit#(1)) selectoutput(SerialFIFOTX#(DataMessage) x);
   return x.out;
endfunction

function PipeIn#(Bit#(1)) selectinput(SerialFIFORX#(DataMessage) x);
   return x.in;
endfunction

function Action move(PipeOut#(DataMessage) from, PipeIn#(DataMessage) to);
   return action
	     $display("move %x", from.first);
	     to.enq(from.first);
	     from.deq();
	  endaction;
endfunction

module mkNocArbitrate#(Vector#(n, Bit#(4)) id, Bit#(4) outlink, Vector#(r, PipeOut#(a)) in, PipeIn#(a) out)(Empty)
/*   provisos(
      Add#(0,n,2),
      Add#(0,r,5)
      ) */ ;
   Arbiter_IFC#(r) arb <- mkArbiter(False);
   for (Integer i = 0; i < valueOf(r); i = i + 1)
      rule send_request (out.notFull && in[i].notEmpty);
	 arb.clients[i].request();
      endrule

   rule move;
      if (out.notFull && in[arb.grant_id].notEmpty)
	 action
	    $display("arb id [%d,%d] link %d from %d", id[0], id[1], outlink, arb.grant_id);
	    out.enq(in[arb.grant_id].first());
	    in[arb.grant_id].deq();
	 endaction
   endrule
endmodule

module mkDistributor#(Vector#(n, Bit#(4)) id, PipeOut#(DataMessage) in, Vector#(r, PipeIn#(DataMessage)) out)(Empty)
/*    provisos(
      Add#(0,n,2),
      Add#(0,r,5)
      ) */
;
   rule move;
      $display("distrib [%d,%d] to [%d,%d] v %x",
	 id[0], id[1], in.first.address[0], in.first.address[1],
	 in.first.payload);
      if (in.first.address[0] < id[0])
	 begin
	    $display(" to link 1");
	    move(in, out[1]);
	 end
      else if (in.first.address[0] > id[0])
	 begin
	    $display(" to link 0");
	    move(in, out[0]);
	 end
      else /* in.first.address[0] == id[0] */
	 begin
	    if (in.first.address[1] < id[1])
	       begin
		  $display(" to link 3");
		  move (in, out[3]);
	       end
	    else if (in.first.address[1] > id[1])
	       begin
		  $display(" to link 2");
		  move (in, out[2]);
	       end
	    else
	       begin
		  $display(" to link 4");
		  move(in, out[4]);
	       end
	 end
   endrule
endmodule

// This makes a FIFO which throws away data and is never ready to read
module mkDiscard(FIFOF#(DataMessage));
   method Action enq(DataMessage d);
   endmethod
   method Bool notFull;
      return True;
   endmethod
   method DataMessage first() = ?;
   method Bool notEmpty();
      return False;
   endmethod
   method Action deq;
      if (False) noAction;
   endmethod
   method Action clear = ?;
endmodule

typedef 2 NumDims;
(* synthesize *)
module mkNocNode#(Vector#(NumDims, Bit#(4)) id)(NocNode#(NumDims));
   Integer radix = (valueOf(NumDims) * 2) + 1;

   // host Links
   FIFOF#(DataMessage) fifofromhost <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) fifotohost <- mkSizedFIFOF(4);
   PipeIn#(DataMessage) tohost = toPipeIn(fifotohost);
   PipeOut#(DataMessage) fromhost = toPipeOut(fifofromhost);

   Vector#(NumDims, SerialFIFOTX#(DataMessage)) txup <- replicateM(mkSerialFIFOTX);
   Vector#(NumDims, SerialFIFORX#(DataMessage)) rxup <- replicateM(mkSerialFIFORX);
   Vector#(NumDims, SerialFIFOTX#(DataMessage)) txdown <- replicateM(mkSerialFIFOTX);
   Vector#(NumDims, SerialFIFORX#(DataMessage)) rxdown <- replicateM(mkSerialFIFORX);

   // sources
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeOut#(DataMessage)) switchin = newVector;
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeIn#(DataMessage)) switchout = newVector;
   // buffers for crossbar switch
   Vector#(TAdd#(TMul#(NumDims, 2), 1), Vector#(TAdd#(TMul#(NumDims, 2), 1), FIFOF#(DataMessage))) xp = replicate(newVector);
   // temps for building switch
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeIn#(DataMessage)) tmpin = newVector;
   Vector#(TAdd#(TMul#(NumDims, 2), 1), PipeOut#(DataMessage)) tmpout = newVector;

   for (Integer i = 0; i < valueOf(NumDims); i = i + 1)
      begin
	 switchin[(2*i) + 0] = rxup[i].out;
	 switchin[(2*i) + 1] = rxdown[i].out;
	 switchout[(2*i) + 0] = txup[i].in;
	 switchout[(2*i) + 1] = txdown[i].in;
      end
   switchin[radix - 1] = fromhost;
   switchout[radix - 1] = tohost;

   for (Integer x = 0; x < radix; x = x + 1)
      for (Integer y = 0; y < radix; y = y + 1)
	 if (x != y) xp[x][y] <- mkSizedFIFOF(4);

   for (Integer x = 0; x < (radix - 1); x = x + 1)
      xp[x][x] <- mkDiscard();

   xp[radix - 1][radix - 1] <- mkSizedFIFOF(4);

   // create distributors

   for (Integer x = 0; x < radix; x = x + 1)
      begin
	 for (Integer y = 0; y < radix; y = y + 1)
	    tmpin[y] = toPipeIn(xp[x][y]);
	 mkDistributor(id, switchin[x], tmpin);
      end
   // create arbiters
   for (Integer y = 0; y < radix; y = y + 1)
      begin
	 for (Integer x = 0; x < radix; x = x + 1)
	    tmpout[x] = toPipeOut(xp[x][y]);
	 mkNocArbitrate(id, truncate(y), tmpout, switchout[y]);
      end

  // interface wiring

   interface PipeIn hosttonode = toPipeIn(fifofromhost);
   interface PipeOut nodetohost = toPipeOut(fifotohost);
   interface Vector linkupin = map(selectinput, rxup);
   interface Vector linkupout = map(selectoutput, txup);
   interface Vector linkdownin = map(selectinput, rxdown);
   interface Vector linkdownout = map(selectoutput, txdown);

endmodule