added rest of toPipeIn and toPipeOut for adapters

Change-Id: I3f8e672b18ad658ca93906c96a2f7e0f79e8ac12

// Copyright (c) 2012 MIT
// Copyright (c) 2012 Nokia, 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 FIFOF          ::*;
import SpecialFIFOs   ::*;
import StmtFSM        ::*;
import Assert         ::*;
import Pipe           ::*;

function Bit#(a) rtruncate(Bit#(b) x) provisos(Add#(k,a,b));
   match {.v,.*} = split(x);
   return v;
endfunction

interface ToBit#(numeric type n, type a);
   method Action enq(a v);
   method Bit#(n) first;
   method Action deq();
   method Bool notEmpty();
   method Bool notFull();
endinterface

interface FromBit#(numeric type n, type a);
   method Action enq(Bit#(n) v);
   method a first();
   method Action deq();
   method Bool notEmpty();
   method Bool notFull();
endinterface

instance ToGet#(FromBit#(n,a),a);
   function Get#(a) toGet(FromBit#(n,a) x);
      return (interface Get
		 method get();
		    actionvalue
		       x.deq;
		       return x.first;
		    endactionvalue
		 endmethod
	      endinterface);
   endfunction
endinstance

instance ToPut#(ToBit#(n,a),a);
   function Put#(a) toPut(ToBit#(n,a) x);
      return (interface Put
		 method put(a v);
		    action
		       x.enq(v);
		    endaction
		 endmethod
	      endinterface);
   endfunction
endinstance

instance ToPipeIn#(Bit#(n), FromBit#(n,a));
   function PipeIn#(Bit#(n)) toPipeIn(FromBit#(n,a) frombit);
      return (interface PipeIn#(Bit#(n));
		 method enq = frombit.enq;
		 method notFull = frombit.notFull;
	      endinterface);
   endfunction
endinstance
instance ToPipeOut#(a, FromBit#(n,a));
   function PipeOut#(a) toPipeOut(FromBit#(n,a) frombit);
      return (interface PipeOut#(a);
		 method first = frombit.first;
		 method deq = frombit.deq;
		 method notEmpty = frombit.notEmpty;
	      endinterface);
   endfunction
endinstance

instance ToPipeIn#(a, ToBit#(n,a));
   function PipeIn#(a) toPipeIn(ToBit#(n,a) tobit);
      return (interface PipeIn#(Bit#(n));
		 method enq = tobit.enq;
		 method notFull = tobit.notFull;
	      endinterface);
   endfunction
endinstance
instance ToPipeOut#(Bit#(n), ToBit#(n,a));
   function PipeOut#(Bit#(n)) toPipeOut(ToBit#(n,a) tobit);
      return (interface PipeOut#(Bit#(n));
		 method first = tobit.first;
		 method deq = tobit.deq;
		 method notEmpty = tobit.notEmpty;
	      endinterface);
   endfunction
endinstance

module mkToBit(ToBit#(n,a))
   provisos(Bits#(a,asz),
            Add#(1, z, asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max  = fromInteger(valueOf(nwords)) - 1;
   Bit#(paddingsz) padding = 0;

   FIFOF#(Bit#(aszn)) fifo <- mkFIFOF1();
   Reg#(Bit#(32))   count <- mkReg(0);

   let nv = valueOf(n);

   method Action enq(a val);
      fifo.enq({padding,pack(val)});
   endmethod

   method Bit#(n) first() if (fifo.notEmpty);
      return rtruncate(fifo.first << (count*fromInteger(nv)));
   endmethod

   method Action deq() if (fifo.notEmpty);
      if (count == max)
         begin
            count <= 0;
            fifo.deq;
         end
      else
         begin
            count <= count + 1;
         end
   endmethod
   method Bool notEmpty = fifo.notEmpty;
   method Bool notFull = fifo.notFull;
endmodule

module mkFromBit(FromBit#(n,a))
   provisos(Bits#(a,asz),
            Add#(1,z,asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max    = fromInteger(valueOf(nwords))-1;

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(32))    count <- mkReg(0);
   FIFOF#(Bit#(asz)) fifo <- mkFIFOF1;

   method Action enq(Bit#(n) x) if (count < max || fifo.notFull);
      Bit#(aszn) newbuff = truncate({fbnbuff,x});
      fbnbuff <= newbuff;
      if (count == max)
         begin
            count <= 0;
            fifo.enq(truncate(newbuff));
         end
      else
         begin
            count <= count+1;
         end
   endmethod

   method a first;
       return unpack(fifo.first);
   endmethod

   method Action deq;
       fifo.deq;
   endmethod

   method Bool notEmpty() = fifo.notEmpty;
   method Bool notFull() = fifo.notFull;
endmodule

module mkAdapterTb(Empty);
   ToBit#(32,Bit#(72)) tb32_72 <- mkToBit();
   ToBit#(32,Bit#(17)) tb32_17 <- mkToBit();

   FromBit#(32,Bit#(72)) fb32_72 <- mkFromBit();
   FromBit#(32,Bit#(17)) fb32_17 <- mkFromBit();

   Reg#(Bit#(10)) timer <- mkReg(0);
   rule timeout;
       timer <= timer+1;
       dynamicAssert(timer < 128, "Timeout");
   endrule

   mkAutoFSM(
      seq

       // test to bit-32
       tb32_72.enq(72'h090807060504030201);
       dynamicAssert(tb32_72.notEmpty, "Adapter not empty");
       dynamicAssert(!tb32_72.notFull, "Adapter full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.notEmpty, tb32_72.notFull);
       $display("tb32_72 word 0 %h", tb32_72.first());
       dynamicAssert(tb32_72.first == 32'h00000009, "expecting 00000009");
       tb32_72.deq;
       $display("tb32_72 word 1 %h", tb32_72.first());
       dynamicAssert(tb32_72.first == 32'h08070605, "expecting 08070605");
       tb32_72.deq;
       $display("tb32_72 word 2 %h", tb32_72.first());
       dynamicAssert(tb32_72.first == 32'h04030201, "expecting 04030201");
       tb32_72.deq;
       dynamicAssert(!tb32_72.notEmpty && tb32_72.notFull, "Adapter empty and not full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.notEmpty, tb32_72.notFull);
       dynamicAssert(!tb32_17.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.notFull, "tb32_17 !full");
       tb32_17.enq(17'h10203);
       dynamicAssert(tb32_17.notEmpty, "tb32_17 not empty");
       dynamicAssert(!tb32_17.notFull, "tb32_17 full");
       $display("tb32_17.first %h", tb32_17.first);
       dynamicAssert(tb32_17.first == (32'h00010203), "Expected 00010203");
       tb32_17.deq;
       dynamicAssert(!tb32_17.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.notFull, "tb32_17 !full");

       //test from bit-32
       dynamicAssert(!fb32_72.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.notFull, "Adapter not full");
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.notEmpty, fb32_72.notFull);
       fb32_72.enq(32'h00000009);
       fb32_72.enq(32'h08070605);
       fb32_72.enq(32'h04030201);
       $display("fb32_72.first %h", fb32_72.first);
       dynamicAssert(fb32_72.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.deq;
       fb32_72.enq(32'h09080706);
       dynamicAssert(!fb32_72.notEmpty, "Adapter not empty");
       dynamicAssert(fb32_72.notFull, "Adapter not full");
       fb32_72.enq(32'h05040302);
       fb32_72.enq(32'h01000000);
       dynamicAssert(fb32_72.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_72.notFull, "Adapter full");
       $display("fb32_72.first %h", fb32_72.first);
       dynamicAssert(fb32_72.first == 72'h060504030201000000, "Expected 060504030201000000");
       fb32_72.deq;
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.notEmpty, fb32_72.notFull);
       dynamicAssert(!fb32_72.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.notFull, "Adapter not full");
       fb32_17.enq(32'h10203);
       dynamicAssert(fb32_17.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_17.notFull, "Adapter full");
       $display("fb32_17.first %h", fb32_17.first);
       dynamicAssert(fb32_17.first == 17'h10203, "Expected 10203");
       fb32_17.deq;
       dynamicAssert(!fb32_17.notEmpty, "Adapter empty");
       dynamicAssert(fb32_17.notFull, "Adapter not full");

       // they should be duals
       tb32_72.enq(72'h090807060504030201);
       fb32_72.enq(tb32_72.first);
       tb32_72.deq;
       fb32_72.enq(tb32_72.first);
       tb32_72.deq;
       fb32_72.enq(tb32_72.first);
       tb32_72.deq;
       dynamicAssert(fb32_72.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.deq;

       tb32_17.enq(17'h10203);
       fb32_17.enq(tb32_17.first);
       tb32_17.deq;
       dynamicAssert(fb32_17.first == 17'h10203, "Expected 10203");
       fb32_17.deq;

       $finish(0);
   endseq
   );

endmodule

// Copyright (c) 2012 MIT
// Copyright (c) 2012 Nokia, 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 FIFOF          ::*;
import SpecialFIFOs   ::*;
import StmtFSM        ::*;
import Assert         ::*;
import Pipe           ::*;

function Bit#(a) rtruncate(Bit#(b) x) provisos(Add#(k,a,b));
   match {.v,.*} = split(x);
   return v;
endfunction

interface ToBit#(numeric type n, type a);
   method Action enq(a v);
   method Bit#(n) first;
   method Action deq();
   method Bool notEmpty();
   method Bool notFull();
endinterface

interface FromBit#(numeric type n, type a);
   method Action enq(Bit#(n) v);
   method a first();
   method Action deq();
   method Bool notEmpty();
   method Bool notFull();
endinterface

instance ToGet#(FromBit#(n,a),a);
   function Get#(a) toGet(FromBit#(n,a) x);
      return (interface Get
		 method get();
		    actionvalue
		       x.deq;
		       return x.first;
		    endactionvalue
		 endmethod
	      endinterface);
   endfunction
endinstance

instance ToPut#(ToBit#(n,a),a);
   function Put#(a) toPut(ToBit#(n,a) x);
      return (interface Put
		 method put(a v);
		    action
		       x.enq(v);
		    endaction
		 endmethod
	      endinterface);
   endfunction
endinstance

instance ToPipeIn#(Bit#(n), FromBit#(n,a));
   function PipeIn#(Bit#(n)) toPipeIn(FromBit#(n,a) in);
      return (interface PipeIn#(Bit#(n));
		 method enq = in.enq;
		 method notFull = in.notFull;
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(Bit#(n), ToBit#(n,a));
   function PipeOut#(Bit#(n)) toPipeOut(ToBit#(n,a) in);
      return (interface PipeOut#(Bit#(n));
		 method first = in.first;
		 method deq = in.deq;
		 method notEmpty = in.notEmpty;
	      endinterface);
   endfunction
endinstance

module mkToBit(ToBit#(n,a))
   provisos(Bits#(a,asz),
            Add#(1, z, asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max  = fromInteger(valueOf(nwords)) - 1;
   Bit#(paddingsz) padding = 0;

   FIFOF#(Bit#(aszn)) fifo <- mkFIFOF1();
   Reg#(Bit#(32))   count <- mkReg(0);

   let nv = valueOf(n);

   method Action enq(a val);
      fifo.enq({padding,pack(val)});
   endmethod

   method Bit#(n) first() if (fifo.notEmpty);
      return rtruncate(fifo.first << (count*fromInteger(nv)));
   endmethod

   method Action deq() if (fifo.notEmpty);
      if (count == max)
         begin
            count <= 0;
            fifo.deq;
         end
      else
         begin
            count <= count + 1;
         end
   endmethod
   method Bool notEmpty = fifo.notEmpty;
   method Bool notFull = fifo.notFull;
endmodule

module mkFromBit(FromBit#(n,a))
   provisos(Bits#(a,asz),
            Add#(1,z,asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max    = fromInteger(valueOf(nwords))-1;

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(32))    count <- mkReg(0);
   FIFOF#(Bit#(asz)) fifo <- mkFIFOF1;

   method Action enq(Bit#(n) x) if (count < max || fifo.notFull);
      Bit#(aszn) newbuff = truncate({fbnbuff,x});
      fbnbuff <= newbuff;
      if (count == max)
         begin
            count <= 0;
            fifo.enq(truncate(newbuff));
         end
      else
         begin
            count <= count+1;
         end
   endmethod

   method a first;
       return unpack(fifo.first);
   endmethod

   method Action deq;
       fifo.deq;
   endmethod

   method Bool notEmpty() = fifo.notEmpty;
   method Bool notFull() = fifo.notFull;
endmodule

module mkAdapterTb(Empty);
   ToBit#(32,Bit#(72)) tb32_72 <- mkToBit();
   ToBit#(32,Bit#(17)) tb32_17 <- mkToBit();

   FromBit#(32,Bit#(72)) fb32_72 <- mkFromBit();
   FromBit#(32,Bit#(17)) fb32_17 <- mkFromBit();

   Reg#(Bit#(10)) timer <- mkReg(0);
   rule timeout;
       timer <= timer+1;
       dynamicAssert(timer < 128, "Timeout");
   endrule

   mkAutoFSM(
      seq

       // test to bit-32
       tb32_72.enq(72'h090807060504030201);
       dynamicAssert(tb32_72.notEmpty, "Adapter not empty");
       dynamicAssert(!tb32_72.notFull, "Adapter full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.notEmpty, tb32_72.notFull);
       $display("tb32_72 word 0 %h", tb32_72.first());
       dynamicAssert(tb32_72.first == 32'h00000009, "expecting 00000009");
       tb32_72.deq;
       $display("tb32_72 word 1 %h", tb32_72.first());
       dynamicAssert(tb32_72.first == 32'h08070605, "expecting 08070605");
       tb32_72.deq;
       $display("tb32_72 word 2 %h", tb32_72.first());
       dynamicAssert(tb32_72.first == 32'h04030201, "expecting 04030201");
       tb32_72.deq;
       dynamicAssert(!tb32_72.notEmpty && tb32_72.notFull, "Adapter empty and not full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.notEmpty, tb32_72.notFull);
       dynamicAssert(!tb32_17.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.notFull, "tb32_17 !full");
       tb32_17.enq(17'h10203);
       dynamicAssert(tb32_17.notEmpty, "tb32_17 not empty");
       dynamicAssert(!tb32_17.notFull, "tb32_17 full");
       $display("tb32_17.first %h", tb32_17.first);
       dynamicAssert(tb32_17.first == (32'h00010203), "Expected 00010203");
       tb32_17.deq;
       dynamicAssert(!tb32_17.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.notFull, "tb32_17 !full");

       //test from bit-32
       dynamicAssert(!fb32_72.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.notFull, "Adapter not full");
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.notEmpty, fb32_72.notFull);
       fb32_72.enq(32'h00000009);
       fb32_72.enq(32'h08070605);
       fb32_72.enq(32'h04030201);
       $display("fb32_72.first %h", fb32_72.first);
       dynamicAssert(fb32_72.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.deq;
       fb32_72.enq(32'h09080706);
       dynamicAssert(!fb32_72.notEmpty, "Adapter not empty");
       dynamicAssert(fb32_72.notFull, "Adapter not full");
       fb32_72.enq(32'h05040302);
       fb32_72.enq(32'h01000000);
       dynamicAssert(fb32_72.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_72.notFull, "Adapter full");
       $display("fb32_72.first %h", fb32_72.first);
       dynamicAssert(fb32_72.first == 72'h060504030201000000, "Expected 060504030201000000");
       fb32_72.deq;
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.notEmpty, fb32_72.notFull);
       dynamicAssert(!fb32_72.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.notFull, "Adapter not full");
       fb32_17.enq(32'h10203);
       dynamicAssert(fb32_17.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_17.notFull, "Adapter full");
       $display("fb32_17.first %h", fb32_17.first);
       dynamicAssert(fb32_17.first == 17'h10203, "Expected 10203");
       fb32_17.deq;
       dynamicAssert(!fb32_17.notEmpty, "Adapter empty");
       dynamicAssert(fb32_17.notFull, "Adapter not full");

       // they should be duals
       tb32_72.enq(72'h090807060504030201);
       fb32_72.enq(tb32_72.first);
       tb32_72.deq;
       fb32_72.enq(tb32_72.first);
       tb32_72.deq;
       fb32_72.enq(tb32_72.first);
       tb32_72.deq;
       dynamicAssert(fb32_72.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.deq;

       tb32_17.enq(17'h10203);
       fb32_17.enq(tb32_17.first);
       tb32_17.deq;
       dynamicAssert(fb32_17.first == 17'h10203, "Expected 10203");
       fb32_17.deq;

       $finish(0);
   endseq
   );

endmodule


simplify writeData admission control in MemWriteEngine

// 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 Vector::*;
import BuildVector::*;
import Cntrs::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import MemTypes::*;
import Pipe::*;
import ConnectalConfig::*;

`include "ConnectalProjectConfig.bsv"

module mkMemWriteEngine(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Add#(1, d__, busWidth)
	    ,Add#(1, d__, userWidth)
	    ,Add#(e__, TLog#(numServers), MemTagSize)
	    ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
	    ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
	    ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	    );
   let rv <- mkMemWriteEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

interface MemWriteChannel#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth);
   interface PipeIn#(Bit#(MemTagSize))        writeGnt; // grants request
   interface PipeOut#(MemRequest)             writeReq;
   interface PipeOut#(MemData#(userWidth))    writeData;
   interface PipeIn#(Bit#(MemTagSize))        writeDone;
   interface MemWriteEngineServer#(userWidth) writeServer;
endinterface

module mkMemWriteChannel#(Integer bufferSizeBytes, Integer channelNumber,
			  PipeOut#(Bit#(MemTagSize)) writeGntPipe, PipeOut#(Bit#(MemTagSize)) writeDonePipe)
   (MemWriteChannel#(busWidth, userWidth, cmdQDepth))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, d__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))       serverCond <- mkFIFO1();
   FIFO#(Tuple2#(Bit#(MemTagSize),MemengineCmd)) serverReq <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(MemTagSize),Bool))inProgress <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(MemTagSize),Bit#(MemTagSize),Bool)) serverDone <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFOF#(MemRequest)           writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();

   Reg#(Bool)              clientInFlight <- mkReg(False);
   Reg#(Bool)              clientBursts <- mkReg(False);
   ConfigCounter#(16)      clientAvail <- mkConfigCounter(0);
   Reg#(MemengineCmd)      clientStart <- mkReg(unpack(0));
   FIFO#(Bool)             clientFinished <- mkSizedFIFO(1);
   FIFOF#(MemengineCmd)    clientCommand <- mkSizedFIFOF(1);
   Count#(Bit#(32))        clientCycles     <- mkCount(0);
   FIFOF#(MemRequestCycles) clientCyclesFifo <- mkFIFOF();
   FIFOF#(Bit#(userWidth)) dataBuffer <- mkSizedBRAMFIFOF(bufferSizeBeats);
   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule rl_cycles;
      cycles <= cycles + 1;
   endrule

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   rule store_cmd if (!clientInFlight);
      let cmd <- toGet(clientCommand).get();
      clientInFlight <= True;
      clientBursts <= True;
      clientStart <= cmd;
      $display("cycles %d starting request %d bytes %d", cycles, cmd.tag, cmd.len);
      clientCycles <= 0;
   endrule
   rule rule_request_cycles;
      clientCycles.incr(1);
   endrule

   rule load_ctxt_a if (!load_in_progress);
      if (clientBursts) begin
	 load_in_progress <= True;
	 let cmd = clientStart;
	 let cond0 <- clientAvail.maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 serverCond.enq(tuple3(cmd,cond0,cond1));
      end
   endrule

   rule load_ctxt_b if (load_in_progress);
      load_in_progress <= False;
      match {.cmd,.cond0,.cond1} <- toGet(serverCond).get;
      if  (cond0) begin
	 //$display("load_ctxt_b cycles %d %h", cycles, cmd.base);
	 serverReq.enq(tuple2(0,cmd));
	 if (cond1) begin
	    clientBursts <= False;
	 end
	 else begin
	    clientStart <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
               burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule rlWriteReq;
      match {.idx, .cmd} <- toGet(serverReq).get;
      Bit#(BurstLenSize) bl = cmd.burstLen;
      Bool last = False;
      if (cmd.len <= extend(bl)) begin
	 last = True;
	 bl = truncate(cmd.len);
      end
      inProgress.enq(tuple3(truncate(bl>>beat_shift), cmd.tag, last));
      //$display("writeReq %d, %h %h %h", channelNumber, cmd.base, bl, last);
      writeReqFifo.enq(MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: fromInteger(channelNumber)});
   endrule

   rule rlWriteData;
      match {.rc, .client_tag, .last} = inProgress.first;
      //let gnt = writeGntPipe.first;
      let new_respCnt = respCnt+1;
      let lastBeat = False;
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 inProgress.deq();
	 //writeGntPipe.deq();
	 serverDone.enq(tuple3(0,client_tag,last));
	 lastBeat = True;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      let wd <- toGet(dataBuffer).get();
      writeDataFifo.enq(MemData{data:wd, tag:fromInteger(channelNumber), last:lastBeat});
   endrule

   rule rlWriteDone;
      let tag <- toGet(writeDonePipe).get();
      match {.idx, .req_tag, .last} <- toGet(serverDone).get;
      if (last) begin
	 clientInFlight <= False;
	 clientFinished.enq(True);
`ifdef MEMENGINE_REQUEST_CYCLES
	 $display("cycles %d req_tag %d clientCycles = %d", cycles, req_tag, clientCycles);
	 clientCyclesFifo.enq(MemRequestCycles { tag: req_tag, cycles: clientCycles });
`endif
      end
      //$display("writeDone %d %d", channelNumber, last);
   endrule

   MemWriteEngineServer#(userWidth) ws = (interface MemWriteEngineServer#(userWidth);
      interface Put request;
	 method Action put(MemengineCmd cmd);
	    Bit#(32) bsb = fromInteger(bufferSizeBytes);
      `ifdef SIMULATION
	    Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
	    Bit#(32) bl = extend(cmd.burstLen);
	    // this is because bsc lifts the divide operation (below)
	    // and on startup the simulator gets a floating-point exception
	    if (bl ==0)
	       bl = 1;
	    let mdw0 = ((cmd.len)/bl)*bl != cmd.len;
	    let mdw1 = ((cmd.len)/dw)*dw != cmd.len;
	    let bbl = extend(cmd.burstLen) > bsb;
	    if(bbl || mdw0 || mdw1 || cmd.len == 0) begin
	       if (bbl)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
	       if (mdw0 || mdw1 || cmd.len == 0)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported len %h mdw0=%d mdw1=%d", cmd.len, mdw0, mdw1);
	    end
	    else
      `endif
	       begin
		  clientCommand.enq(cmd);
		  $display("(%d) %h %h %h", channelNumber, cmd.base, cmd.len, cmd.burstLen);
	       end
	 endmethod
      endinterface
      interface Get done;
	 method ActionValue#(Bool) get = toGet(clientFinished).get;
      endinterface
      interface PipeIn data = interface PipeIn;
				 method Bool notFull = dataBuffer.notFull;
   				 method Action enq(Bit#(userWidth) v);
				    dataBuffer.enq(v);
				    clientAvail.increment(1);
				 endmethod
			      endinterface;
	 interface PipeOut requestCycles = toPipeOut(clientCyclesFifo);
	 endinterface);
   interface writeServer = ws;
   interface writeReq = toPipeOut(writeReqFifo);
   interface writeData = toPipeOut(writeDataFifo);
endmodule

module mkMemWriteEngineBuff#(Integer bufferSizeBytes)(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, a__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     ,Add#(b__, TLog#(numServers), MemTagSize)
             ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
             ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
             ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	     );

   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();
   function Tuple2#(Bit#(TLog#(numServers)),Bit#(MemTagSize)) tagDone(Bit#(MemTagSize) tag);
      return tuple2(truncate(tag), tag);
   endfunction
`ifdef ARB_FUNNEL
   FIFOF#(Bit#(MemTagSize))       arbFifo <- mkFIFOF1();
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) arbPipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(arbFifo))));
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) donePipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(writeDoneFifo))));
`else
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   arbFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) arbPipes = map(toPipeOut, arbFifos);
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   doneFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) donePipes = map(toPipeOut, doneFifos);
`endif
   Vector#(numServers, MemWriteChannel#(busWidth,userWidth,cmdQDepth)) writeChannels <- zipWith3M(mkMemWriteChannel(bufferSizeBytes),
												  genVector(),
												  arbPipes,
												  donePipes);
   function PipeOut#(MemRequest) writeChannelDmaWriteReq(Integer i);
      return writeChannels[i].writeReq;
   endfunction
   function PipeOut#(MemData#(userWidth)) writeChannelDmaWriteData(Integer i);
      return writeChannels[i].writeData;
   endfunction
   function MemWriteEngineServer#(userWidth) writeChannelServer(Integer i);
      return writeChannels[i].writeServer;
   endfunction

   Reg#(Bool)         reqInFlight <- mkReg(False);
   Reg#(Bool)         reqNotDone  <- mkReg(False);
   Reg#(Bit#(TLog#(numServers))) currentChannel <- mkReg(0);
   FIFOF#(MemRequest)          writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkSizedFIFOF(16);
   FunnelPipe#(1,numServers,MemRequest,2) reqFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteReq));
//   FunnelPipe#(1,numServers,MemData#(userWidth),2) dataFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteData));

   rule rl_arbitration if (!reqInFlight && !reqNotDone);
      let req <- toGet(reqFunnel[0]).get();
      // tag is channel number
      currentChannel <= truncate(req.tag);
      reqNotDone  <= True;
      writeReqFifo.enq(req);
      reqInFlight <= True;
   endrule
   rule rl_writeData if (reqInFlight);
      MemData#(userWidth) md <- toGet(writeChannels[currentChannel].writeData).get();
      if (md.last)
	 reqInFlight <= False;
      writeDataFifo.enq(md);
   endrule

   rule rl_writeDone;
      let tag <- toGet(writeDoneFifo).get();
      doneFifos[tag].enq(tag);
      reqNotDone  <= False;
   endrule

   interface writeServers = genWith(writeChannelServer);
   interface MemWriteClient dmaClient;
      interface writeReq = toGet(writeReqFifo);
      interface writeData = toGet(writeDataFifo);
      interface writeDone = toPut(writeDoneFifo);
   endinterface: dmaClient

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 Vector::*;
import BuildVector::*;
import Cntrs::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import MemTypes::*;
import Pipe::*;
import ConnectalConfig::*;

`include "ConnectalProjectConfig.bsv"

module mkMemWriteEngine(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Add#(1, d__, busWidth)
	    ,Add#(1, d__, userWidth)
	    ,Add#(e__, TLog#(numServers), MemTagSize)
	    ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
	    ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
	    ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	    );
   let rv <- mkMemWriteEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

interface MemWriteChannel#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth);
   interface PipeIn#(Bit#(MemTagSize))        writeGnt; // grants request
   interface PipeOut#(MemRequest)             writeReq;
   interface PipeOut#(MemData#(userWidth))    writeData;
   interface PipeIn#(Bit#(MemTagSize))        writeDone;
   interface MemWriteEngineServer#(userWidth) writeServer;
endinterface

module mkMemWriteChannel#(Integer bufferSizeBytes, Integer channelNumber,
			  PipeOut#(Bit#(MemTagSize)) writeGntPipe, PipeOut#(Bit#(MemTagSize)) writeDonePipe)
   (MemWriteChannel#(busWidth, userWidth, cmdQDepth))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, d__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))       serverCond <- mkFIFO1();
   FIFO#(Tuple2#(Bit#(MemTagSize),MemengineCmd)) serverReq <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(MemTagSize),Bool))inProgress <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(MemTagSize),Bit#(MemTagSize),Bool)) serverDone <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFOF#(MemRequest)           writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();

   Reg#(Bool)              clientInFlight <- mkReg(False);
   Reg#(Bool)              clientBursts <- mkReg(False);
   ConfigCounter#(16)      clientAvail <- mkConfigCounter(0);
   Reg#(MemengineCmd)      clientStart <- mkReg(unpack(0));
   FIFO#(Bool)             clientFinished <- mkSizedFIFO(1);
   FIFOF#(MemengineCmd)    clientCommand <- mkSizedFIFOF(1);
   Count#(Bit#(32))        clientCycles     <- mkCount(0);
   FIFOF#(MemRequestCycles) clientCyclesFifo <- mkFIFOF();
   FIFOF#(Bit#(userWidth)) dataBuffer <- mkSizedBRAMFIFOF(bufferSizeBeats);
   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule rl_cycles;
      cycles <= cycles + 1;
   endrule

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   rule store_cmd if (!clientInFlight);
      let cmd <- toGet(clientCommand).get();
      clientInFlight <= True;
      clientBursts <= True;
      clientStart <= cmd;
      $display("cycles %d starting request %d bytes %d", cycles, cmd.tag, cmd.len);
      clientCycles <= 0;
   endrule
   rule rule_request_cycles;
      clientCycles.incr(1);
   endrule

   rule load_ctxt_a if (!load_in_progress);
      if (clientBursts) begin
	 load_in_progress <= True;
	 let cmd = clientStart;
	 let cond0 <- clientAvail.maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 serverCond.enq(tuple3(cmd,cond0,cond1));
      end
   endrule

   rule load_ctxt_b if (load_in_progress);
      load_in_progress <= False;
      match {.cmd,.cond0,.cond1} <- toGet(serverCond).get;
      if  (cond0) begin
	 //$display("load_ctxt_b cycles %d %h", cycles, cmd.base);
	 serverReq.enq(tuple2(0,cmd));
	 if (cond1) begin
	    clientBursts <= False;
	 end
	 else begin
	    clientStart <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
               burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule rlWriteReq;
      match {.idx, .cmd} <- toGet(serverReq).get;
      Bit#(BurstLenSize) bl = cmd.burstLen;
      Bool last = False;
      if (cmd.len <= extend(bl)) begin
	 last = True;
	 bl = truncate(cmd.len);
      end
      inProgress.enq(tuple3(truncate(bl>>beat_shift), cmd.tag, last));
      //$display("writeReq %d, %h %h %h", channelNumber, cmd.base, bl, last);
      writeReqFifo.enq(MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: fromInteger(channelNumber)});
   endrule

   rule rlWriteData;
      match {.rc, .client_tag, .last} = inProgress.first;
      let gnt = writeGntPipe.first;
      let new_respCnt = respCnt+1;
      let lastBeat = False;
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 inProgress.deq();
	 writeGntPipe.deq();
	 serverDone.enq(tuple3(0,client_tag,last));
	 lastBeat = True;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      let wd <- toGet(dataBuffer).get();
      writeDataFifo.enq(MemData{data:wd, tag:fromInteger(channelNumber), last:lastBeat});
   endrule

   rule rlWriteDone;
      let tag <- toGet(writeDonePipe).get();
      match {.idx, .req_tag, .last} <- toGet(serverDone).get;
      if (last) begin
	 clientInFlight <= False;
	 clientFinished.enq(True);
`ifdef MEMENGINE_REQUEST_CYCLES
	 $display("cycles %d req_tag %d clientCycles = %d", cycles, req_tag, clientCycles);
	 clientCyclesFifo.enq(MemRequestCycles { tag: req_tag, cycles: clientCycles });
`endif
      end
      //$display("writeDone %d %d", channelNumber, last);
   endrule

   MemWriteEngineServer#(userWidth) ws = (interface MemWriteEngineServer#(userWidth);
      interface Put request;
	 method Action put(MemengineCmd cmd);
	    Bit#(32) bsb = fromInteger(bufferSizeBytes);
      `ifdef SIMULATION
	    Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
	    Bit#(32) bl = extend(cmd.burstLen);
	    // this is because bsc lifts the divide operation (below)
	    // and on startup the simulator gets a floating-point exception
	    if (bl ==0)
	       bl = 1;
	    let mdw0 = ((cmd.len)/bl)*bl != cmd.len;
	    let mdw1 = ((cmd.len)/dw)*dw != cmd.len;
	    let bbl = extend(cmd.burstLen) > bsb;
	    if(bbl || mdw0 || mdw1 || cmd.len == 0) begin
	       if (bbl)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
	       if (mdw0 || mdw1 || cmd.len == 0)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported len %h mdw0=%d mdw1=%d", cmd.len, mdw0, mdw1);
	    end
	    else
      `endif
	       begin
		  clientCommand.enq(cmd);
		  $display("(%d) %h %h %h", channelNumber, cmd.base, cmd.len, cmd.burstLen);
	       end
	 endmethod
      endinterface
      interface Get done;
	 method ActionValue#(Bool) get = toGet(clientFinished).get;
      endinterface
      interface PipeIn data = interface PipeIn;
				 method Bool notFull = dataBuffer.notFull;
   				 method Action enq(Bit#(userWidth) v);
				    dataBuffer.enq(v);
				    clientAvail.increment(1);
				 endmethod
			      endinterface;
	 interface PipeOut requestCycles = toPipeOut(clientCyclesFifo);
	 endinterface);
   interface writeServer = ws;
   interface writeReq = toPipeOut(writeReqFifo);
   interface writeData = toPipeOut(writeDataFifo);
endmodule

module mkMemWriteEngineBuff#(Integer bufferSizeBytes)(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, a__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     ,Add#(b__, TLog#(numServers), MemTagSize)
             ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
             ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
             ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	     );

   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();
   function Tuple2#(Bit#(TLog#(numServers)),Bit#(MemTagSize)) tagDone(Bit#(MemTagSize) tag);
      return tuple2(truncate(tag), tag);
   endfunction
`ifdef ARB_FUNNEL
   FIFOF#(Bit#(MemTagSize))       arbFifo <- mkFIFOF1();
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) arbPipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(arbFifo))));
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) donePipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(writeDoneFifo))));
`else
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   arbFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) arbPipes = map(toPipeOut, arbFifos);
   Vector#(numServers, FIFOF#(Bit#(MemTagSize)))   doneFifos <- replicateM(mkFIFOF);
   Vector#(numServers, PipeOut#(Bit#(MemTagSize))) donePipes = map(toPipeOut, doneFifos);
`endif
   Vector#(numServers, MemWriteChannel#(busWidth,userWidth,cmdQDepth)) writeChannels <- zipWith3M(mkMemWriteChannel(bufferSizeBytes),
												  genVector(),
												  arbPipes,
												  donePipes);
   function PipeOut#(MemRequest) writeChannelDmaWriteReq(Integer i);
      return writeChannels[i].writeReq;
   endfunction
   function PipeOut#(MemData#(userWidth)) writeChannelDmaWriteData(Integer i);
      return writeChannels[i].writeData;
   endfunction
   function MemWriteEngineServer#(userWidth) writeChannelServer(Integer i);
      return writeChannels[i].writeServer;
   endfunction

   Reg#(Bool)         reqInFlight <- mkReg(False);
   FIFOF#(MemRequest)          writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkSizedFIFOF(16);
   FunnelPipe#(1,numServers,MemRequest,2) reqFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteReq));
   FunnelPipe#(1,numServers,MemData#(userWidth),2) dataFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteData));

   rule rl_arbitration if (!reqInFlight);
      let req <- toGet(reqFunnel[0]).get();
      // tag is channel number
`ifdef ARB_FUNNEL
      arbFifo.enq(req.tag);
`else
      arbFifos[req.tag].enq(req.tag);
`endif
      writeReqFifo.enq(req);
      reqInFlight <= True;
   endrule
   rule rl_writeData if (reqInFlight);
      MemData#(userWidth) md <- toGet(dataFunnel[0]).get();
      if (md.last)
	 reqInFlight <= False;
      writeDataFifo.enq(md);
   endrule

`ifndef ARB_FUNNEL
   rule rl_writeDone;
      let tag <- toGet(writeDoneFifo).get();
      doneFifos[tag].enq(tag);
   endrule
`endif

   interface writeServers = genWith(writeChannelServer);
   interface MemWriteClient dmaClient;
      interface writeReq = toGet(writeReqFifo);
      interface writeData = toGet(writeDataFifo);
      interface writeDone = toPut(writeDoneFifo);
   endinterface: dmaClient

endmodule


added MmDebugRequestPortal enum tag

added MmDebugRequestPortal enum tag

// 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.

typedef 20 MMSize;

`ifdef DataBusWidth
typedef TDiv#(`DataBusWidth,32) N;
`else
`ifndef N_VALUE
typedef 2 N;
`else
typedef `N_VALUE N;
`endif
`endif

`ifndef J_VALUE
typedef 2 J;
`else
typedef `J_VALUE J;
`endif
`ifndef K_VALUE
typedef 2 K;
`else
typedef `K_VALUE K;
`endif

typedef TMin#(4,J) RowsPerTile;
typedef TDiv#(J,RowsPerTile) T;

typedef 15 BurstLen;

typedef 4 SourceBufferSize;

typedef TMul#(32,N) DmaSz;

typedef enum {
   DmaConfigPortal,
   DmaIndicationPortal,
   MmIndicationPortal,
   MmRequestPortal,
   RbmIndicationPortal,
   RbmRequestPortal,
   SigmoidIndicationPortal,
   SigmoidRequestPortal,
   TimerIndicationPortal,
   TimerRequestPortal,
   FpMacRequestPortal,
   FpMacIndicationPortal,
   MmDebugRequestPortal,
   MmDebugIndicationPortal
} IfcNames deriving (Eq,Bits);

interface MmIndication;
   method Action mmfDone(Bit#(64) cycles);
endinterface

interface MmRequest;
   method Action mmf(Bit#(32) inPointer1, Bit#(32) r1, Bit#(32) c1,
		     Bit#(32) inPointer2, Bit#(32) r2, Bit#(32) c2,
		     Bit#(32) outPointer);
endinterface

interface SigmoidIndication;
   method Action sigmoidDone();
   method Action sigmoidTableSize(Bit#(32) size);
   method Action sigmoidTableUpdated(Bit#(32) addr);
endinterface

interface SigmoidRequest;
    method Action sigmoid(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
    method Action setSigmoidLimits(Bit#(32) rscale, Bit#(32) llimit, Bit#(32) ulimit);
    method Action sigmoidTableSize();
    method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
endinterface

interface RbmIndication;
   method Action statesDone();
   method Action statesDone2();
   method Action updateWeightsDone();
   method Action sumOfErrorSquared(Bit#(32) error);
   method Action dbg(Bit#(32) a, Bit#(32) b, Bit#(32) c, Bit#(32) d);
endinterface

interface RbmRequest;
   method Action sglist(Bit#(32) off, Bit#(40) addr, Bit#(32) len);
   method Action paref(Bit#(32) addr, Bit#(32) len);

   method Action bramMmf(Bit#(32) inPointer1, Bit#(32) r1, Bit#(32) c1,
			 Bit#(32) inPointer2, Bit#(32) r2, Bit#(32) c2,
			 Bit#(32) outPointer);
   method Action toBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);
   method Action fromBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);

    method Action computeStates(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
    method Action computeStates2(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) readPointer2, Bit#(32) readOffset2,
				 Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);

    method Action updateWeights(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Bit#(32) learningRateOverNumExamples);

    method Action sumOfErrorSquared(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);

    method Action dbg();
    method Action finish(); // for bsim only
endinterface

interface MmDebugIndication;
   method Action started();
   method Action startSourceAndSink(UInt#(32) startA, UInt#(32) startC, Int#(32) jint);
endinterface

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

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

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

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

typedef 20 MMSize;

`ifdef DataBusWidth
typedef TDiv#(`DataBusWidth,32) N;
`else
`ifndef N_VALUE
typedef 2 N;
`else
typedef `N_VALUE N;
`endif
`endif

`ifndef J_VALUE
typedef 2 J;
`else
typedef `J_VALUE J;
`endif
`ifndef K_VALUE
typedef 2 K;
`else
typedef `K_VALUE K;
`endif

typedef TMin#(4,J) RowsPerTile;
typedef TDiv#(J,RowsPerTile) T;

typedef 15 BurstLen;

typedef 4 SourceBufferSize;

typedef TMul#(32,N) DmaSz;

typedef enum {
   DmaConfigPortal,
   DmaIndicationPortal,
   MmIndicationPortal,
   MmRequestPortal,
   RbmIndicationPortal,
   RbmRequestPortal,
   SigmoidIndicationPortal,
   SigmoidRequestPortal,
   TimerIndicationPortal,
   TimerRequestPortal,
   FpMacRequestPortal,
   FpMacIndicationPortal,
   MmDebugIndicationPortal
} IfcNames deriving (Eq,Bits);

interface MmIndication;
   method Action mmfDone(Bit#(64) cycles);
endinterface

interface MmRequest;
   method Action mmf(Bit#(32) inPointer1, Bit#(32) r1, Bit#(32) c1,
		     Bit#(32) inPointer2, Bit#(32) r2, Bit#(32) c2,
		     Bit#(32) outPointer);
endinterface

interface SigmoidIndication;
   method Action sigmoidDone();
   method Action sigmoidTableSize(Bit#(32) size);
   method Action sigmoidTableUpdated(Bit#(32) addr);
endinterface

interface SigmoidRequest;
    method Action sigmoid(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
    method Action setSigmoidLimits(Bit#(32) rscale, Bit#(32) llimit, Bit#(32) ulimit);
    method Action sigmoidTableSize();
    method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
endinterface

interface RbmIndication;
   method Action statesDone();
   method Action statesDone2();
   method Action updateWeightsDone();
   method Action sumOfErrorSquared(Bit#(32) error);
   method Action dbg(Bit#(32) a, Bit#(32) b, Bit#(32) c, Bit#(32) d);
endinterface

interface RbmRequest;
   method Action sglist(Bit#(32) off, Bit#(40) addr, Bit#(32) len);
   method Action paref(Bit#(32) addr, Bit#(32) len);

   method Action bramMmf(Bit#(32) inPointer1, Bit#(32) r1, Bit#(32) c1,
			 Bit#(32) inPointer2, Bit#(32) r2, Bit#(32) c2,
			 Bit#(32) outPointer);
   method Action toBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);
   method Action fromBram(Bit#(32) off, Bit#(32) pointer, Bit#(32) offset, Bit#(32) numElts);

    method Action computeStates(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);
    method Action computeStates2(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) readPointer2, Bit#(32) readOffset2,
				 Bit#(32) writePointer, Bit#(32) writeOffset, Bit#(32) numElts);

    method Action updateWeights(Bit#(32) posAssociationsPointer, Bit#(32) negAssociationsPointer, Bit#(32) weightsPointer, Bit#(32) numElts, Bit#(32) learningRateOverNumExamples);

    method Action sumOfErrorSquared(Bit#(32) dataPointer, Bit#(32) predPointer, Bit#(32) numElts);

    method Action dbg();
    method Action finish(); // for bsim only
endinterface

interface MmDebugIndication;
   method Action started();
   method Action startSourceAndSink(UInt#(32) startA, UInt#(32) startC, Int#(32) jint);
endinterface


put incoming data in data register (read only access from outside) add ready bit, clearable by outside

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

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

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

import FIFO::*;

/* This is a serial to parallel converter for messages of type a
 * The data register is assumed to always be available, so an arriving
 * message must be removed ASAP or be overwritten
 */
interface LinkIn#(type a);
   method Action frame(bit f);
   method Action data(bit d);
   interface Reg#(Bool) dataready;
   interface ReadOnly#(a) ror;
endinterface

module mkLinkIn(LinkIn#(a))
       provisos(Bits#(a,asize)),
	        Log#(asize, k);

   // registers for receiving data messages
   Reg#(bit) framebit <- mkReg(0);
   Reg#(bit) databit <- mkReg(0);
   Reg#(Bit#(6)) incount <= mkReg(0);
   Reg#(a) shifter <- mkReg(0);
   Reg#(a) data <- mkReg(0);
   FIFOF#(?) <- mkSizedFIFOF(1);

   rule handleDataFrame;
      if (datainframebit == 0)
	 begin
            dataincount <= 0;
	 end
      else
	 dataincount <= dataincount + 1;
   endrule

   rule handleDataInShift (datainframebit == 1);
      Bit#(SizeOf(DataMessage)) tmp = datainshifter;
      tmp = tmp >> 1;
      tmp[SizeOf(DataMessage)-1] = datainbit;
      datainshifter <= tmp;
      if (dataincount == (SizeOf(DataMessage) - 1))
         action
	    data <= tmp;
	    dataready <= True;
	 end;
   endrule

   interface LinkIn;

      method Action frame(bit i );
	 frameinbit <= i ;
      endmethod

      method Action data( bit i );
	 datainbit <= i;
      endmethod

      interface ReadOnly#(a) ror = regToReadOnly(r);

      interface Reg#(Bool) ready = dataready;

   endinterface

endmodule

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

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

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

import FIFO::*;

/* This is a serial to parallel converter for messages of type a
 * The data register is assumed to always be available, so an arriving
 * message must be removed ASAP or be overwritten
 */
interface LinkIn#(type a);
   method Action frame(bit f);
   method Action data(bit d);
   interface Reg#(Bool) dataready;
   interface ReadOnly#(a) ror;
endinterface

module mkLinkIn(LinkIn#(a))
       provisos(Bits#(a,asize)),
	        Log#(asize, k);

   // registers for receiving data messages
   Reg#(bit) framebit <- mkReg(0);
   Reg#(bit) databit <- mkReg(0);
   Reg#(Bit#(6)) incount <= mkReg(0);
   Reg#(a) shifter <- mkReg(0);
   Reg#(a) data <- mkReg(0);
   FIFOF#(?) <- mkSizedFIFOF(1);

   rule handleDataFrame;
      if (datainframebit == 0)
	 begin
            dataincount <= 0;
	 end
      else
	 dataincount <= dataincount + 1;
   endrule

   rule handleDataInShift (datainframebit == 1);
      Bit#(SizeOf(DataMessage)) tmp = datainshifter;
      tmp = tmp >> 1;
      tmp[SizeOf(DataMessage)-1] = datainbit;
      datainshifter <= tmp;
      if (dataincount == (SizeOf(DataMessage) - 1))
         action
	    new <= tmp;
	    dataready <= True;
	 end;
   endrule

   interface LinkIn;

      method Action frame(bit i );
	 frameinbit <= i ;
      endmethod

      method Action data( bit i );
	 datainbit <= i;
      endmethod

      interface ReadOnly#(a) ror = regToReadOnly(r);

      interface Reg#(Bool) ready = dataready;

   endinterface

endmodule


Fixed verilator compilation if RS232 or SPI is not enabled

// Copyright (c) 2017 Massachusetts Institute of Technology

// 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 "ProcConfig.bsv"

// ProcVerilator.bsv
// This is a wrapper to translate the generic Proc interface to an interface
// that is accepted by connectal.

import RS232::*;

// This assumes a Proc.bsv file that contains the mkProc definition
import Abstraction::*;
import BuildVector::*;
import ClientServer::*;
import Clocks::*;
import Connectable::*;
import FIFO::*;
import GetPut::*;
import Port::*;
import Proc::*;
import Vector::*;
import VerificationPacket::*;
import VerificationPacketFilter::*;
import ProcPins::*;
import RVTypes::*;

import SimRam::*;

interface ProcVerilator;
    // Processor Control
    method Action start();
    method Action stop();
    method Action stallPipeline(Bool stall);

    // Verification
    method Maybe#(VerificationPacket) currVerificationPacket;

    // TODO: re-enable this port
    // interface UncachedMemClientPort mmio;
    interface GenericMemServerPort#(XLEN) extmem;
    // Interrupts
    method Action triggerExternalInterrupt;

    method Action sendUartChar(Bit#(8) x);
    method ActionValue#(Bit#(8)) receiveUartChar;
endinterface

module mkProcVerilator(ProcVerilator);
    GenericMemServerPort#(MainMemoryWidth) simRam <- mkSimRam(`CONFIG_RAM_INIT_HEX_FILE);
    Proc#(MainMemoryWidth) proc <- mkProc;

    // connect the processor to the simRam
    mkConnection(proc.ram, simRam);

`ifdef CONFIG_SPI
    rule tieOff;
        proc.pins.spi.miso(0);
    endrule
`endif

`ifdef CONFIG_RS232
    Reg#(Bit#(16)) uartDivisor <- mkReg(17);
    UART#(16) simUart <- mkUART(8, NONE, STOP_1, uartDivisor);
    let uartSimToFPGABridge <- mkConnection(toPut(proc.pins.uart.sin), toGet(simUart.rs232.sout));
    let uartFPGAToSimBridge <- mkConnection(toPut(simUart.rs232.sin), toGet(proc.pins.uart.sout));

    rule displayMsg;
        let x <- simUart.tx.get();
        $write("%c", x);
    endrule
`endif

    // Processor Control
    method Action start;
        proc.start;
    endmethod
    method Action stop();
        proc.stop;
    endmethod
    method Action stallPipeline(Bool stall);
        proc.stallPipeline(stall);
    endmethod

    // Verification
    method Maybe#(VerificationPacket) currVerificationPacket;
        return proc.currVerificationPacket;
    endmethod

    // Uncached Connections
    // interface UncachedMemClientPort mmio = proc.mmio;
    // External Connections
    interface GenericMemServerPort extmem = proc.extmem;
    // Interrupts
    method Action triggerExternalInterrupt = proc.triggerExternalInterrupt;

`ifdef CONFIG_RS232
    method Action sendUartChar(Bit#(8) x);
        simUart.rx.put(x);
    endmethod
    method ActionValue#(Bit#(8)) receiveUartChar;
        let x <- simUart.tx.get;
        return x;
    endmethod
`else
    method Action sendUartChar(Bit#(8) x) if (False);
        noAction;
    endmethod
    method ActionValue#(Bit#(8)) receiveUartChar if (False);
        return ?;
    endmethod
`endif
endmodule

// Copyright (c) 2017 Massachusetts Institute of Technology

// 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 "ProcConfig.bsv"

// ProcVerilator.bsv
// This is a wrapper to translate the generic Proc interface to an interface
// that is accepted by connectal.

import RS232::*;

// This assumes a Proc.bsv file that contains the mkProc definition
import Abstraction::*;
import BuildVector::*;
import ClientServer::*;
import Clocks::*;
import Connectable::*;
import FIFO::*;
import GetPut::*;
import Port::*;
import Proc::*;
import Vector::*;
import VerificationPacket::*;
import VerificationPacketFilter::*;
import ProcPins::*;
import RVTypes::*;

import SimRam::*;

interface ProcVerilator;
    // Processor Control
    method Action start(Bit#(64) startPc);
    method Action stop();
    method Action stallPipeline(Bool stall);

    // Verification
    method Maybe#(VerificationPacket) currVerificationPacket;

    // TODO: re-enable this port
    // interface UncachedMemClientPort mmio;
    interface GenericMemServerPort#(XLEN) extmem;
    // Interrupts
    method Action triggerExternalInterrupt;

    method Action sendUartChar(Bit#(8) x);
    method ActionValue#(Bit#(8)) receiveUartChar;
endinterface

module mkProcVerilator(ProcVerilator);
    GenericMemServerPort#(MainMemoryWidth) simRam <- mkSimRam(`CONFIG_RAM_INIT_HEX_FILE);
    Proc#(MainMemoryWidth) proc <- mkProc;

    // connect the processor to the simRam
    mkConnection(proc.ram, simRam);

    rule tieOff;
        proc.pins.spi.miso(0);
    endrule

    Reg#(Bit#(16)) uartDivisor <- mkReg(17);
    UART#(16) simUart <- mkUART(8, NONE, STOP_1, uartDivisor);
    let uartSimToFPGABridge <- mkConnection(toPut(proc.pins.uart.sin), toGet(simUart.rs232.sout));
    let uartFPGAToSimBridge <- mkConnection(toPut(simUart.rs232.sin), toGet(proc.pins.uart.sout));

    rule displayMsg;
        let x <- simUart.tx.get();
        $write("%c", x);
    endrule

    // Processor Control
    method Action start(Bit#(64) startPc);
        proc.start(startPc);
    endmethod
    method Action stop();
        proc.stop;
    endmethod
    method Action stallPipeline(Bool stall);
        proc.stallPipeline(stall);
    endmethod

    // Verification
    method Maybe#(VerificationPacket) currVerificationPacket;
        return proc.currVerificationPacket;
    endmethod

    // Uncached Connections
    // interface UncachedMemClientPort mmio = proc.mmio;
    // External Connections
    interface GenericMemServerPort extmem = proc.extmem;
    // Interrupts
    method Action triggerExternalInterrupt = proc.triggerExternalInterrupt;

    method Action sendUartChar(Bit#(8) x);
        simUart.rx.put(x);
    endmethod
    method ActionValue#(Bit#(8)) receiveUartChar;
        let x <- simUart.tx.get;
        return x;
    endmethod
endmodule


remove synthesis boundary on mkPcieHostTop.  memread_manual works again

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

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

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

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

import Vector            :: *;
import Clocks            :: *;
import GetPut            :: *;
import FIFO              :: *;
import Connectable       :: *;
import ClientServer      :: *;
import DefaultValue      :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import Xilinx            :: *;
import PCIEWRAPPER       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemSlaveEngine    :: *;
import MemMasterEngine   :: *;
import PcieCsr           :: *;
import MemSlave          :: *;
import MemTypes          :: *;
import Bscan             :: *;
`ifndef BSIM
import PcieEndpointX7    :: *;
`endif
import HostInterface    :: *;

`ifndef DataBusWidth
`define DataBusWidth 64
`endif
`ifndef PinType
`define PinType Empty
`endif

`ifdef USES_BSCAN
`define BSCAN_ARG  local_bscan
`else
`define BSCAN_ARG
`endif
typedef `PinType PinType;

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

(* synthesize *)
module  mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   Clock epClock125 <- exposeCurrentClock();
   Reset epReset125 <- exposeCurrentReset();
   let dispatcher <- mkTLPDispatcher;
   let arbiter    <- mkTLPArbiter;
   Vector#(NumberOfMasters,MemSlaveEngine#(DataBusWidth)) sEngine <- replicateM(mkMemSlaveEngine(my_pciId));
   Vector#(NumberOfMasters,MemSlave#(40,DataBusWidth)) slavearr;
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
   BscanTop bscan <- mkBscanTop(3); // Use USER3  (JTAG IDCODE address 0x22)
   BscanLocal lbscan <- mkBscanLocal(bscan, clocked_by bscan.tck, reset_by bscan.rst);

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

   PcieTracer  traceif <- mkPcieTracer();
   mkConnection(traceif.bus, (interface Client;
                                 interface request = arbiter.outToBus;
                                 interface response = dispatcher.inFromBus;
                              endinterface));
`ifndef BSIM
   Reg#(Bit#(TAdd#(TlpTraceAddrSize,1))) bscanPcieTraceBramWrAddrReg <- mkReg(0);
   BscanBram#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) pcieBscanBram <- mkBscanBram(127, bscanPcieTraceBramWrAddrReg, lbscan.loc[1]);
   mkConnection(pcieBscanBram.bramClient, traceif.tlpdata.bscanBramServer);
   rule tdorule;
      lbscan.loc[1].tdo(pcieBscanBram.data_out());
   endrule
`endif

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs(traceif.tlpdata);
   MemSlave#(32,32) my_slave <- mkMemSlave(csr.client);
   mkConnection(mvec[portConfig].master, my_slave);

   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = slavearr;
   interface interruptRequest = intr.interruptRequest;
   interface pci = traceif.pci;
   interface BscanTop bscanif = lbscan.loc[0];
endmodule: mkPcieHost

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

`ifdef BSIM
module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   let dc <- exposeCurrentClock;
   let dr <- exposeCurrentReset;
   Clock epClock125 = dc;
   Reset epReset125 = dr;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(PciId{ bus:0, dev:0, func:0});
   // connect pciehost.pci to bdip functions here
   rule from_bdpi if (can_get_tlp);
      TLPData#(16) foo <- get_tlp;
      pciehost.pci.response.put(foo);
      //$display("from_bdpi: %h %d", foo, valueOf(SizeOf#(TLPData#(16))));
   endrule
   rule to_bdpi if (can_put_tlp);
      TLPData#(16) foo <- pciehost.pci.request.get;
      put_tlp(foo);
      //$display("to_bdpi");
   endrule
   interface Clock tepClock125 = epClock125;
   interface Reset tepReset125 = epReset125;
   interface PcieHost tpciehost = pciehost;
endmodule
`else // not BSIM
//(* synthesize, no_default_clock, no_default_reset *)
(* no_default_clock, no_default_reset *)
module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   Clock sys_clk_200mhz <- mkClockIBUFDS(sys_clk_p, sys_clk_n);
   Clock sys_clk_200mhz_buf <- mkClockBUFG(clocked_by sys_clk_200mhz);
   Clock pci_clk_100mhz_buf <- mkClockIBUFDS_GTE2(True, pci_sys_clk_p, pci_sys_clk_n);
   // Instantiate the PCIE endpoint
   PcieEndpointX7#(PcieLanes) ep7 <- mkPcieEndpointX7( clocked_by pci_clk_100mhz_buf
						      , reset_by pci_sys_reset_n
						       );

   Clock epClock125 = ep7.epClock125;
   Reset epReset125 = ep7.epReset125;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(
         PciId{ bus:  ep7.cfg.bus_number(), dev: ep7.cfg.device_number(), func: ep7.cfg.function_number()},
         clocked_by epClock125, reset_by epReset125);
   mkConnection(ep7.tlp, pciehost.pci, clocked_by epClock125, reset_by epReset125);
   interface Clock tsys_clk_200mhz = sys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf = sys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf = pci_clk_100mhz_buf;
   interface PcieEndpointX7 tep7 = ep7;
   interface Clock tepClock125 = epClock125;
   interface Reset tepReset125 = epReset125;
   interface PcieHost tpciehost = pciehost;

   //once the dot product server makes timing, replace epClock125 with ep7.epclock250
   interface doubleClock = epClock125;
   interface doubleReset = epReset125;

endmodule
`endif

`ifndef BSIM
(* no_default_clock, no_default_reset *)
`endif
module mkPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)
   (PcieTop#(PinType));

   PcieHostTop host <- mkPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n);

`ifdef IMPORT_HOSTIF
   PortalTop#(40, DataBusWidth, PinType, NumberOfMasters) portalTop <- mkPortalTop(host, clocked_by host.tepClock125, reset_by host.tepReset125);
`else
   PortalTop#(40, DataBusWidth, PinType, NumberOfMasters) portalTop <- mkPortalTop(clocked_by host.tepClock125, reset_by host.tepReset125);
`endif
   mkConnection(host.tpciehost.master, portalTop.slave, clocked_by host.tepClock125, reset_by host.tepReset125);
   if (valueOf(NumberOfMasters) > 0) begin
      mapM(uncurry(mkConnection),zip(portalTop.masters, host.tpciehost.slave));
   end

   // going from level to edge-triggered interrupt
   Vector#(15, Reg#(Bool)) interruptRequested <- replicateM(mkReg(False, clocked_by host.tepClock125, reset_by host.tepReset125));
   rule interrupt_rule;
     Integer intr_num = 0;
     for (Integer i = 0; i < 15; i = i + 1) begin
	 if (intr_num == 0 && portalTop.interrupt[i] && !interruptRequested[i])
             intr_num = i+1;
	 interruptRequested[i] <= portalTop.interrupt[i];
     end
     if (intr_num != 0) begin // i= 0 for the directory
        MSIX_Entry msixEntry = host.tpciehost.msixEntry[intr_num];
        host.tpciehost.interruptRequest.put(tuple2({msixEntry.addr_hi, msixEntry.addr_lo}, msixEntry.msg_data));
     end
   endrule

`ifndef BSIM
   interface pcie = host.tep7.pcie;
   method Bit#(NumLeds) leds();
      return extend({host.tep7.user.lnk_up(),3'd2});
   endmethod
   interface pins = portalTop.pins;
`endif
endmodule

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

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

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

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

import Vector            :: *;
import Clocks            :: *;
import GetPut            :: *;
import FIFO              :: *;
import Connectable       :: *;
import ClientServer      :: *;
import DefaultValue      :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import Xilinx            :: *;
import PCIEWRAPPER       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemSlaveEngine    :: *;
import MemMasterEngine   :: *;
import PcieCsr           :: *;
import MemSlave          :: *;
import MemTypes          :: *;
import Bscan             :: *;
`ifndef BSIM
import PcieEndpointX7    :: *;
`endif
import HostInterface    :: *;

`ifndef DataBusWidth
`define DataBusWidth 64
`endif
`ifndef PinType
`define PinType Empty
`endif

`ifdef USES_BSCAN
`define BSCAN_ARG  local_bscan
`else
`define BSCAN_ARG
`endif
typedef `PinType PinType;

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

(* synthesize *)
module  mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   Clock epClock125 <- exposeCurrentClock();
   Reset epReset125 <- exposeCurrentReset();
   let dispatcher <- mkTLPDispatcher;
   let arbiter    <- mkTLPArbiter;
   Vector#(NumberOfMasters,MemSlaveEngine#(DataBusWidth)) sEngine <- replicateM(mkMemSlaveEngine(my_pciId));
   Vector#(NumberOfMasters,MemSlave#(40,DataBusWidth)) slavearr;
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
   BscanTop bscan <- mkBscanTop(3); // Use USER3  (JTAG IDCODE address 0x22)
   BscanLocal lbscan <- mkBscanLocal(bscan, clocked_by bscan.tck, reset_by bscan.rst);

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

   PcieTracer  traceif <- mkPcieTracer();
   mkConnection(traceif.bus, (interface Client;
                                 interface request = arbiter.outToBus;
                                 interface response = dispatcher.inFromBus;
                              endinterface));
`ifndef BSIM
   Reg#(Bit#(TAdd#(TlpTraceAddrSize,1))) bscanPcieTraceBramWrAddrReg <- mkReg(0);
   BscanBram#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) pcieBscanBram <- mkBscanBram(127, bscanPcieTraceBramWrAddrReg, lbscan.loc[1]);
   mkConnection(pcieBscanBram.bramClient, traceif.tlpdata.bscanBramServer);
   rule tdorule;
      lbscan.loc[1].tdo(pcieBscanBram.data_out());
   endrule
`endif

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs(traceif.tlpdata);
   MemSlave#(32,32) my_slave <- mkMemSlave(csr.client);
   mkConnection(mvec[portConfig].master, my_slave);

   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = slavearr;
   interface interruptRequest = intr.interruptRequest;
   interface pci = traceif.pci;
   interface BscanTop bscanif = lbscan.loc[0];
endmodule: mkPcieHost

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

`ifdef BSIM
module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   let dc <- exposeCurrentClock;
   let dr <- exposeCurrentReset;
   Clock epClock125 = dc;
   Reset epReset125 = dr;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(PciId{ bus:0, dev:0, func:0});
   // connect pciehost.pci to bdip functions here
   rule from_bdpi if (can_get_tlp);
      TLPData#(16) foo <- get_tlp;
      pciehost.pci.response.put(foo);
      //$display("from_bdpi: %h %d", foo, valueOf(SizeOf#(TLPData#(16))));
   endrule
   rule to_bdpi if (can_put_tlp);
      TLPData#(16) foo <- pciehost.pci.request.get;
      put_tlp(foo);
      //$display("to_bdpi");
   endrule
   interface Clock tepClock125 = epClock125;
   interface Reset tepReset125 = epReset125;
   interface PcieHost tpciehost = pciehost;
endmodule
`else // not BSIM
(* synthesize, no_default_clock, no_default_reset *)
module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);
   Clock sys_clk_200mhz <- mkClockIBUFDS(sys_clk_p, sys_clk_n);
   Clock sys_clk_200mhz_buf <- mkClockBUFG(clocked_by sys_clk_200mhz);
   Clock pci_clk_100mhz_buf <- mkClockIBUFDS_GTE2(True, pci_sys_clk_p, pci_sys_clk_n);
   // Instantiate the PCIE endpoint
   PcieEndpointX7#(PcieLanes) ep7 <- mkPcieEndpointX7( clocked_by pci_clk_100mhz_buf
						      , reset_by pci_sys_reset_n
						       );

   Clock epClock125 = ep7.epClock125;
   Reset epReset125 = ep7.epReset125;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(
         PciId{ bus:  ep7.cfg.bus_number(), dev: ep7.cfg.device_number(), func: ep7.cfg.function_number()},
         clocked_by epClock125, reset_by epReset125);
   mkConnection(ep7.tlp, pciehost.pci, clocked_by epClock125, reset_by epReset125);
   interface Clock tsys_clk_200mhz = sys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf = sys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf = pci_clk_100mhz_buf;
   interface PcieEndpointX7 tep7 = ep7;
   interface Clock tepClock125 = epClock125;
   interface Reset tepReset125 = epReset125;
   interface PcieHost tpciehost = pciehost;

   //once the dot product server makes timing, replace epClock125 with ep7.epclock250
   interface doubleClock = epClock125;
   interface doubleReset = epReset125;

endmodule
`endif

`ifndef BSIM
(* no_default_clock, no_default_reset *)
`endif
module mkPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)
   (PcieTop#(PinType));

   PcieHostTop host <- mkPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n);

`ifdef IMPORT_HOSTIF
   PortalTop#(40, DataBusWidth, PinType, NumberOfMasters) portalTop <- mkPortalTop(host, clocked_by host.tepClock125, reset_by host.tepReset125);
`else
   PortalTop#(40, DataBusWidth, PinType, NumberOfMasters) portalTop <- mkPortalTop(clocked_by host.tepClock125, reset_by host.tepReset125);
`endif
   mkConnection(host.tpciehost.master, portalTop.slave, clocked_by host.tepClock125, reset_by host.tepReset125);
   if (valueOf(NumberOfMasters) > 0) begin
      mapM(uncurry(mkConnection),zip(portalTop.masters, host.tpciehost.slave));
   end

   // going from level to edge-triggered interrupt
   Vector#(15, Reg#(Bool)) interruptRequested <- replicateM(mkReg(False, clocked_by host.tepClock125, reset_by host.tepReset125));
   rule interrupt_rule;
     Integer intr_num = 0;
     for (Integer i = 0; i < 15; i = i + 1) begin
	 if (intr_num == 0 && portalTop.interrupt[i] && !interruptRequested[i])
             intr_num = i+1;
	 interruptRequested[i] <= portalTop.interrupt[i];
     end
     if (intr_num != 0) begin // i= 0 for the directory
        MSIX_Entry msixEntry = host.tpciehost.msixEntry[intr_num];
        host.tpciehost.interruptRequest.put(tuple2({msixEntry.addr_hi, msixEntry.addr_lo}, msixEntry.msg_data));
     end
   endrule

`ifndef BSIM
   interface pcie = host.tep7.pcie;
   method Bit#(NumLeds) leds();
      return extend({host.tep7.user.lnk_up(),3'd2});
   endmethod
   interface pins = portalTop.pins;
`endif
endmodule


works again

works again

// 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 StackReg::*;
import StmtFSM::*;

interface FibIndication;
    method Action fibresult(Bit#(32) v);
    method Action fibnote(Bit#(32) v);
endinterface

interface FibRequest;
   method Action fib(Bit#(32) v);
endinterface

typedef enum {FIBSTATEIDLE, FIBSTATE1, FIBSTATE2,
   FIBSTATE2A, FIBSTATE3, FIBSTATE4, FIBSTATECOMPLETE} FSState
deriving (Bits,Eq);

module mkFibRequest#(FibIndication indication)(FibRequest);

   /* pc, args, vars */
   StackReg#(128, FSState, Bit#(16), Bit#(16)) frame <- mkStackReg(128, FIBSTATEIDLE);

   /* function variables that do not need to be saved or restored
    *    in the pseudocode below, this is tmp2
    */
   Reg#(Bit#(16)) fibretval <- mkReg(0);

   /* experiment: recursive fibonnaci
    * fib(n):
    *   int tmp1, tmp2;
    *   if n == 0 return 0  // fibstate1
    *   if n == 1 return 1
    *   tmp1 = fib(n-1)
    *   tmp2 = fib(n-2      // fibstate2
    *   return tmp1 + tmp2  // fibstate3
    */

   rule fib1 (frame.pc == FIBSTATE1);
      //$display("FIBSTATE1 %d", frame.args);
      if (frame.args == 0)
	 begin
	    fibretval <= 0;
	    frame.doreturn();
	 end
     else if (frame.args == 1)
	begin
	   fibretval <= 1;
	   frame.doreturn();
	end
     else
	frame.docall(FIBSTATE1, FIBSTATE2, frame.args - 1);
     endrule

   rule fib2 (frame.pc == FIBSTATE2);
      //$display("FIBSTATE2 (retval %d)", fibretval);
      frame.vars <= fibretval;
      frame.nextpc(FIBSTATE2A);
   endrule

   /* This state is here so the return value can get into frame.vars before
    * the next call
    */
   rule fib2a (frame.pc == FIBSTATE2A);
      //$display("FIBSTATE2A (retval %d)", fibretval);
      frame.docall(FIBSTATE1, FIBSTATE3, frame.args - 2);
   endrule

   rule fib3 (frame.pc == FIBSTATE3);
      //$display("FIBSTATE3 tmp1 %d fibretval %d return %d", frame.vars, fibretval, frame.vars + fibretval);
      fibretval <= frame.vars + fibretval;
      frame.nextpc(FIBSTATE4);
   endrule

// stall cycle to avoid doreturns in adjacent cycles
   rule fib4 (frame.pc == FIBSTATE4);
      //$display("FIBSTATE4 ");
      frame.doreturn();
   endrule

   rule fibcomplete (frame.pc == FIBSTATECOMPLETE);
      //$display("FIBSTATECOMPLETE %d %d", frame.args, fibretval);
      indication.fibresult(zeroExtend(fibretval));
      frame.nextpc(FIBSTATEIDLE);
   endrule

   method Action fib(Bit#(32) v);
      //$display("request fib %d", v);
      frame.docall(FIBSTATE1, FIBSTATECOMPLETE, truncate(v));
   endmethod

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 StackReg::*;
import StmtFSM::*;

interface FibIndication;
    method Action fibresult(Bit#(32) v);
    method Action fibnote(Bit#(32) v);
endinterface

interface FibRequest;
   method Action fib(Bit#(32) v);
endinterface

typedef enum {FIBSTATEIDLE, FIBSTATE1, FIBSTATE2,
   FIBSTATE3, FIBSTATE4, FIBSTATECOMPLETE} FSState
deriving (Bits,Eq);

module mkFibRequest#(FibIndication indication)(FibRequest);

   /* pc, args, vars */
   StackReg#(128, FSState, Bit#(16), Bit#(16)) frame <- mkStackReg(128, FIBSTATEIDLE);

   /* function variables that do not need to be saved or restored
    *    in the pseudocode below, this is tmp2
    */
   Reg#(Bit#(16)) fibretval <- mkReg(0);

   /* experiment: recursive fibonnaci
    * fib(n):
    *   int tmp1, tmp2;
    *   if n == 0 return 0  // fibstate1
    *   if n == 1 return 1
    *   tmp1 = fib(n-1)
    *   tmp2 = fib(n-2      // fibstate2
    *   return tmp1 + tmp2  // fibstate3
    */

   rule fib1 (frame.pc == FIBSTATE1);
      $display("FIBSTATE1 %d", frame.args);
      if (frame.args == 0)
	 begin
	    fibretval <= 0;
	    frame.doreturn();
	 end
     else if (frame.args == 1)
	begin
	   fibretval <= 1;
	   frame.doreturn();
	end
     else
	frame.docall(FIBSTATE1, FIBSTATE2, frame.args - 1);
     endrule

   rule fib2 (frame.pc == FIBSTATE2);
      $display("FIBSTATE2");
      frame.vars <= fibretval;
      frame.docall(FIBSTATE1, FIBSTATE3, frame.args - 2);
   endrule

   rule fib3 (frame.pc == FIBSTATE3);
      $display("FIBSTATE3 tmp1 %d fibretval %d return %d", frame.vars, fibretval, frame.vars + fibretval);
      fibretval <= frame.vars + fibretval;
      frame.nextpc(FIBSTATE4);
   endrule

// stall cycle to avoid doreturns in adjacent cycles
   rule fib4 (frame.pc == FIBSTATE4);
      $display("FIBSTATE4 ");
      frame.doreturn();
   endrule

   rule fibcomplete (frame.pc == FIBSTATECOMPLETE);
      $display("FIBSTATECOMPLETE %d %d", frame.args, fibretval);
      indication.fibresult(zeroExtend(fibretval));
      frame.nextpc(FIBSTATEIDLE);
   endrule

   method Action fib(Bit#(32) v);
      $display("request fib %d", v);
      frame.docall(FIBSTATE1, FIBSTATECOMPLETE, truncate(v));
   endmethod

endmodule