reformat

reformat

interface RingBuffer;
   method Action set(Bit#(2) regist, Bit#(40) addr);
   method Bit#(40) get(Bit#(2) regist);
//   method Get#(CommandStruct);
//   method Put#(StatusStruct);
endinterface

module mkRingBuffer(RingBuffer);

   Reg#(Bit#(40)) bufferbase <- mkReg(0);
   Reg#(Bit#(40)) bufferend <- mkReg(0);
   Reg#(Bit#(40)) bufferfirst <- mkReg(0);
   Reg#(Bit#(40)) bufferlast <- mkReg(0);

   method Action set(Bit#(2) regist, Bit#(40) addr);
      if (regist == 0) bufferbase <= addr;
      else if (regist == 1) bufferend <= addr;
      else if (regist == 2) bufferfirst <= addr;
      else bufferlast <= addr;
   endmethod

   method Bit#(40) get(Bit#(2) regist);
      if (regist == 0) return (bufferbase);
      else if (regist == 1) return (bufferend);
      else if (regist == 2) return (bufferfirst);
      else return(bufferlast);
   endmethod
endmodule

interface RingBuffer;
	  method Action set(Bit#(2) regist, Bit#(40) addr);
	  method Bit#(40) get(Bit#(2) regist);
endinterface

module mkRingBuffer(RingBuffer);

	Reg#(Bit#(40)) bufferbase <- mkReg(0);
	Reg#(Bit#(40)) bufferend <- mkReg(0);
	Reg#(Bit#(40)) bufferfirst <- mkReg(0);
	Reg#(Bit#(40)) bufferlast <- mkReg(0);

	method Action set(Bit#(2) regist, Bit#(40) addr);
	  if (regist == 0) bufferbase <= addr;
	  else if (regist == 1) bufferend <= addr;
	  else if (regist == 2) bufferfirst <= addr;
	  else bufferlast <= addr;
	  endmethod

	  method Bit#(40) get(Bit#(2) regist);
	    if (regist == 0) return (bufferbase);
	    else if (regist == 1) return (bufferend);
	    else if (regist == 2) return (bufferfirst);
	    else return(bufferlast);
	    endmethod
endmodule


Revert "change static elab in MemReadEngine"

This reverts commit ffaab7a0e02bf2939b1f2c299f79b308927d4cc5.

// 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 FIFOF::*;
import FIFO::*;
import GetPut::*;
import Assert::*;
import ClientServer::*;
import BRAM::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import Connectable::*;
import ConnectalMemory::*;
import MemTypes::*;
import Pipe::*;
import MemUtils::*;

module mkMemReadEngine(MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(busWidth, 8), 8, busWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(busWidth, 0, userWidth)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(d__, TLog#(numServers), 6)
	    );
   let rv <- mkMemReadEngineBuff(valueOf(cmdQDepth) * valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemReadEngineBuff#(Integer bufferSizeBytes) (MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos (Div#(busWidth,8,busWidthBytes),
	     Mul#(busWidthBytes,8,busWidth),
	     Log#(busWidthBytes,beatShift),
	     Log#(cmdQDepth,logCmdQDepth),
	     Mul#(cmdQDepth,numServers,cmdBuffSz),
	     Log#(cmdBuffSz, cmdBuffAddrSz),
	     Log#(numServers, serverIdxSz),
	     Add#(busWidth, 0, userWidth),
	     Add#(1,logCmdQDepth, outCntSz),
	     Add#(1, c__, numServers),
	     Add#(b__, TLog#(numServers), cmdBuffAddrSz),
	     Add#(e__, TLog#(numServers), TAdd#(1, cmdBuffAddrSz)),
	     Add#(a__, serverIdxSz, cmdBuffAddrSz),
	     Min#(2,TLog#(numServers),bpc),
	     Add#(d__, TLog#(numServers), TAdd#(1, serverIdxSz)),
	     Add#(f__, serverIdxSz, 6));

   let verbose = False;

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Vector#(numServers, Reg#(Bool))          clientInFlight <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))  clientAvail <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))  clientCommand <- replicateM(mkReg(unpack(0)));
   Vector#(numServers, Reg#(Bool))          clientFirstBurst <- replicateM(mkReg(False));

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple5#(MemengineCmd,Bool,Bool,Bool,Bit#(BurstLenSize)))              serverCheckAvail <- mkSizedFIFO(1);
   FIFO#(Tuple5#(Bit#(serverIdxSz),MemengineCmd,Bool,Bool,Bit#(BurstLenSize))) serverRequest <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple4#(Bit#(8),Bit#(serverIdxSz),Bool,Bool)) serverProcessing <- mkSizedFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(MemengineCmd)) clientRequest <- replicateM(mkFIFO());

   FIFOF#(MemData#(busWidth))                       serverDataFifo <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemDataF#(userWidth))) clientDataFifo <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(MemDataF#(userWidth)) mem_data_out(PipeOut#(MemDataF#(userWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method MemDataF#(userWidth) first;
	     return inpipe.first;
	  endmethod
	  method Action deq;
	     if (verbose) $display("mkMemReadEngineBuff::check_out: idx %d data %h clientAvail %d eob %d", i, inpipe.first.data, clientAvail[i].read(), inpipe.first.last);
	     inpipe.deq;
	     clientAvail[i].increment(1);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(MemDataF#(userWidth))) memDataPipes = zipWith(mem_data_out, map(toPipeOut,clientDataFifo), genVector);

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   Reg#(Bit#(TAdd#(1,serverIdxSz))) loadIdx <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   let cmd_q_depth = fromInteger(valueOf(cmdQDepth));
   Reg#(Bit#(32)) counter <- mkReg(0);

   rule incCounter;
      counter <= counter + 1;
   endrule

   function Action incr_loadIdx =
      (action
       if(loadIdx+1 >= fromInteger(valueOf(numServers)))
	  loadIdx <= 0;
       else
	  loadIdx <= loadIdx+1;
       endaction);

   for (Integer idx = 0; idx < valueOf(numServers); idx = idx + 1)
      rule store_cmd if (!clientInFlight[idx]);
	 let cmd <- toGet(clientRequest[idx]).get();
	 clientInFlight[idx] <= True;
	 clientCommand[idx] <= cmd;
	 clientFirstBurst[idx] <= True;
	 if (verbose) $display("mkMemReadEngineBuff::%d store_cmd %d %d", counter, idx, clientAvail[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (clientInFlight[loadIdx]) begin
	 load_in_progress <= True;
	 let cmd = clientCommand[loadIdx];
	 let first_burst = clientFirstBurst[loadIdx];
         let last_burst = cmd.len <= extend(cmd.burstLen);
         Bit#(BurstLenSize) cmd_len = cmd.burstLen;
	 if (last_burst)
             cmd_len = truncate(cmd.len);
	 let cond0 <- clientAvail[loadIdx].maybeDecrement(unpack(extend(cmd_len>>beat_shift)));
	 serverCheckAvail.enq(tuple5(cmd,cond0,first_burst,last_burst,cmd_len));
	 if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b clientAvail[%d] %d burstLen %d cond0 %d last_burst %d", counter, loadIdx, clientAvail[loadIdx].read(), cmd_len>>beat_shift, cond0, last_burst);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for clientInFlight to avoid the need for this pragma
   (* descending_urgency = "load_ctxt_c, store_cmd" *)
   rule load_ctxt_c if (load_in_progress);
      load_in_progress <= False;
      incr_loadIdx;
      match {.cmd,.cond0,.first_burst,.last_burst,.cmd_len} <- toGet(serverCheckAvail).get;
      if  (cond0) begin
	 if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", counter, cmd.len, loadIdx, cond0, last_burst);
	 serverRequest.enq(tuple5(truncate(loadIdx),cmd,first_burst,last_burst,cmd_len));
	 clientFirstBurst[loadIdx] <= False;
	 if (last_burst) begin
	    if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b last_burst %d", counter, last_burst);
	    clientInFlight[loadIdx] <= False;
	 end
	 else begin
	    clientCommand[loadIdx] <= 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 read_data_rule;
      let d <- toGet(serverDataFifo).get();
      match {.rc, .idx, .first_burst, .last_burst} = serverProcessing.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("mkMemReadEngineBuff::%d data %h new_respCnt %d rc %d last_burst %d idx %d clientInFlight %d eob %d", counter, d.data, new_respCnt, rc, last_burst, idx, clientInFlight[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 serverProcessing.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      clientDataFifo[idx].enq(MemDataF { data: d.data, tag: d.tag,
         first: //first_burst &&
(respCnt == 0), last: l});
   endrule

   Vector#(numServers, MemReadEngineServer#(userWidth)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface MemReadEngineServer#(userWidth);
		  interface Put request;
		     method Action put(MemengineCmd cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef SIMULATION
			Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
			let mdw = ((cmd.len)/dw)*dw != cmd.len;
			let bbl = extend(cmd.burstLen) > bsb;
			if(bbl || mdw) begin
			   if (bbl)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
			   if (mdw)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported len %d", cmd.len);
			end
			else
`endif
                           begin
			   clientRequest[i].enq(cmd);
			   end
 		     endmethod
		  endinterface
                  interface data = memDataPipes[i];
               endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd, .first_burst, .last_burst, .bl} <- toGet(serverRequest).get;
	    serverProcessing.enq(tuple4(truncate(bl>>beat_shift), idx, first_burst, last_burst));
	    if (verbose) $display("MemReadEngine::%d readReq idx %d offset %h burstLenBytes %h last_burst %d", counter, idx, cmd.base, bl, last_burst);
	    return MemRequest { sglId: cmd.sglId, offset: cmd.base, burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)
`ifdef BYTE_ENABLES
			       , firstbe: maxBound, lastbe: maxBound
`endif
};
	 endmethod
      endinterface
      interface Put readData = toPut(serverDataFifo);
   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.
import Vector::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Assert::*;
import ClientServer::*;
import BRAM::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import Connectable::*;
import ConnectalMemory::*;
import MemTypes::*;
import Pipe::*;
import MemUtils::*;

module mkMemReadEngine(MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(busWidth, 8), 8, busWidth)
	    ,Add#(1, a__, numServers)
	    ,Add#(busWidth, 0, userWidth)
	    ,Add#(b__, TLog#(numServers), TAdd#(1, TLog#(TMul#(cmdQDepth,numServers))))
	    ,Add#(c__, TLog#(numServers), TLog#(TMul#(cmdQDepth, numServers)))
	    ,Add#(d__, TLog#(numServers), 6)
	    );
   let rv <- mkMemReadEngineBuff(valueOf(cmdQDepth) * valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemReadEngineBuff#(Integer bufferSizeBytes) (MemReadEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos (Div#(busWidth,8,busWidthBytes),
	     Mul#(busWidthBytes,8,busWidth),
	     Log#(busWidthBytes,beatShift),
	     Log#(cmdQDepth,logCmdQDepth),
	     Mul#(cmdQDepth,numServers,cmdBuffSz),
	     Log#(cmdBuffSz, cmdBuffAddrSz),
	     Log#(numServers, serverIdxSz),
	     Add#(busWidth, 0, userWidth),
	     Add#(1,logCmdQDepth, outCntSz),
	     Add#(1, c__, numServers),
	     Add#(b__, TLog#(numServers), cmdBuffAddrSz),
	     Add#(e__, TLog#(numServers), TAdd#(1, cmdBuffAddrSz)),
	     Add#(a__, serverIdxSz, cmdBuffAddrSz),
	     Min#(2,TLog#(numServers),bpc),
	     Add#(d__, TLog#(numServers), TAdd#(1, serverIdxSz)),
	     Add#(f__, serverIdxSz, 6));

   let verbose = False;

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Vector#(numServers, Reg#(Bool))          clientInFlight <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))  clientAvail <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))  clientCommand <- replicateM(mkReg(unpack(0)));
   Vector#(numServers, Reg#(Bit#(32)))      clientLen <- replicateM(mkReg(unpack(0)));
   Vector#(numServers, Reg#(Bool))          clientFirstBurst <- replicateM(mkReg(False));

   FIFO#(Tuple5#(MemengineCmd,Bool,Bool,Bool,Bit#(BurstLenSize)))              serverCheckAvail <- mkSizedFIFO(1);
   FIFO#(Tuple7#(Bit#(serverIdxSz),SGLId,Bit#(MemOffsetSize),Bit#(MemTagSize),Bool,Bool,Bit#(BurstLenSize))) serverRequest <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple4#(Bit#(8),Bit#(serverIdxSz),Bool,Bool)) serverProcessing <- mkSizedFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(MemengineCmd)) clientRequest <- replicateM(mkFIFO());

   FIFOF#(MemData#(busWidth))                       serverDataFifo <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemDataF#(userWidth))) clientDataFifo <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(MemDataF#(userWidth)) mem_data_out(PipeOut#(MemDataF#(userWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method MemDataF#(userWidth) first;
	     return inpipe.first;
	  endmethod
	  method Action deq;
	     if (verbose) $display("mkMemReadEngineBuff::check_out: idx %d data %h clientAvail %d eob %d", i, inpipe.first.data, clientAvail[i].read(), inpipe.first.last);
	     inpipe.deq;
	     clientAvail[i].increment(1);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(MemDataF#(userWidth))) memDataPipes = zipWith(mem_data_out, map(toPipeOut,clientDataFifo), genVector);

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

   rule incCounter;
      counter <= counter + 1;
   endrule

   for (Integer idx = 0; idx < valueOf(numServers); idx = idx + 1) begin
      rule store_cmd if (!clientInFlight[idx]);
	 let cmd <- toGet(clientRequest[idx]).get();
	 clientInFlight[idx] <= True;
	 clientCommand[idx] <= cmd;
	 clientLen[idx] <= cmd.len;
	 clientFirstBurst[idx] <= True;
	 if (verbose) $display("mkMemReadEngineBuff::%d store_cmd %d %d", counter, idx, clientAvail[idx].read);
      endrule

      rule load_ctxt_a;
         if (clientInFlight[idx]) begin
	    let cmd = clientCommand[idx];
	    let first_burst = clientFirstBurst[idx];
            let last_burst = cmd.len <= extend(cmd.burstLen);
            Bit#(BurstLenSize) cmd_len = cmd.burstLen;
	    if (last_burst)
                cmd_len = truncate(cmd.len);
	    let cond0 <- clientAvail[idx].maybeDecrement(unpack(extend(cmd_len>>beat_shift)));
	    serverCheckAvail.enq(tuple5(cmd,cond0,first_burst,last_burst,cmd_len));
	    if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b clientAvail[%d] %d burstLen %d cond0 %d last_burst %d", counter, idx, clientAvail[idx].read(), cmd_len>>beat_shift, cond0, last_burst);
         end
      endrule

      // should use an EHR for clientInFlight to avoid the need for this pragma
      (* descending_urgency = "load_ctxt_c, store_cmd" *)
      rule load_ctxt_c;
         match {.cmd,.cond0,.first_burst,.last_burst,.cmd_len} <- toGet(serverCheckAvail).get;
         if  (cond0) begin
	    if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", counter, cmd.len, idx, cond0, last_burst);
	    serverRequest.enq(tuple7(fromInteger(idx),cmd.sglId,cmd.base,cmd.tag,first_burst,last_burst,cmd_len));
	    clientFirstBurst[idx] <= False;
	    if (last_burst) begin
	       if (verbose) $display("mkMemReadEngineBuff::%d load_ctxt_b last_burst %d", counter, last_burst);
	       clientInFlight[idx] <= False;
	    end
	    else begin
	       clientCommand[idx] <= 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
   end //idx

   rule read_data_rule;
      let d <- toGet(serverDataFifo).get();
      match {.rc, .idx, .first_burst, .last_burst} = serverProcessing.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("mkMemReadEngineBuff::%d data %h new_respCnt %d rc %d last_burst %d idx %d clientInFlight %d eob %d", counter, d.data, new_respCnt, rc, last_burst, idx, clientInFlight[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 serverProcessing.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      clientDataFifo[idx].enq(MemDataF { data: d.data, tag: d.tag,
         first: //first_burst &&
(respCnt == 0), last: l});
   endrule

   Vector#(numServers, MemReadEngineServer#(userWidth)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface MemReadEngineServer#(userWidth);
		  interface Put request;
		     method Action put(MemengineCmd cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef SIMULATION
			Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
			let mdw = ((cmd.len)/dw)*dw != cmd.len;
			let bbl = extend(cmd.burstLen) > bsb;
			if(bbl || mdw) begin
			   if (bbl)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
			   if (mdw)
			      $display("XXXXXXXXXX mkMemReadEngineBuff::unsupported len %d", cmd.len);
			end
			else
`endif
                           begin
			   clientRequest[i].enq(cmd);
			   end
 		     endmethod
		  endinterface
                  interface data = memDataPipes[i];
               endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd_sglId, .cmd_base, .cmd_tag, .first_burst, .last_burst, .bl} <- toGet(serverRequest).get;
	    serverProcessing.enq(tuple4(truncate(bl>>beat_shift), idx, first_burst, last_burst));
	    if (verbose) $display("MemReadEngine::%d readReq idx %d offset %h burstLenBytes %h last_burst %d", counter, idx, cmd_base, bl, last_burst);
	    return MemRequest { sglId: cmd_sglId, offset: cmd_base, burstLen:bl, tag: (cmd_tag << valueOf(serverIdxSz)) | extend(idx)
`ifdef BYTE_ENABLES
			       , firstbe: maxBound, lastbe: maxBound
`endif
};
	 endmethod
      endinterface
      interface Put readData = toPut(serverDataFifo);
   endinterface
endmodule


another bsim fix for memcpy

another bsim fix for memcpy

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;

// for PCIE
import Connectable       :: *;
import Xilinx            :: *;
import XilinxPCIE        :: *;
import Xilinx7PcieBridge :: *;
import PcieToAxiBridge   :: *;

// portz libraries
import AxiClientServer::*;
import AxiMasterSlave::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import BlueScope::*;
import AxiRDMA::*;
import BsimRDMA::*;
import PortalMemory::*;
import PortalRMemory::*;

// generated by tool
import MemcpyRequestWrapper::*;
import BlueScopeRequestWrapper::*;
import DMARequestWrapper::*;
import MemcpyIndicationProxy::*;
import BlueScopeIndicationProxy::*;
import DMAIndicationProxy::*;

// defined by user
import Memcpy::*;

module mkPortalTop(StdPortalDmaTop);

   DMAIndicationProxy dmaIndicationProxy <- mkDMAIndicationProxy(9);
   // Max burst 16
   DMAReadBuffer#(64,8) dma_stream_read_chan <- mkDMAReadBuffer();

   // Max burst 16
   DMAWriteBuffer#(64,8) dma_stream_write_chan <- mkDMAWriteBuffer();

   // Max burst 1 because it only reads one word at a time
   DMAReadBuffer#(64,1) dma_word_read_chan <- mkDMAReadBuffer();

   // Max burst 16
   DMAWriteBuffer#(64,8) dma_debug_write_chan <- mkDMAWriteBuffer();

   Vector#(2,  DMAReadClient#(64))   readClients = newVector();
   readClients[0] = dma_stream_read_chan.dmaClient;
   readClients[1] = dma_word_read_chan.dmaClient;

   Vector#(2, DMAWriteClient#(64)) writeClients = newVector();
   writeClients[0] = dma_stream_write_chan.dmaClient;
   writeClients[1] = dma_debug_write_chan.dmaClient;

`ifdef BSIM
   BsimDMAServer#(64)     dma <- mkBsimDMAServer(dmaIndicationProxy.ifc, readClients, writeClients);
`else
   Integer               numRequests = 8;
   AxiDMAServer#(64,8)   dma <- mkAxiDMAServer(dmaIndicationProxy.ifc, numRequests, readClients, writeClients);
`endif

   DMARequestWrapper dmaRequestWrapper <- mkDMARequestWrapper(1005,dma.request);

   BlueScopeIndicationProxy blueScopeIndicationProxy <- mkBlueScopeIndicationProxy(8);
   BlueScope bs <- mkBlueScope(32, dma_debug_write_chan.dmaServer, blueScopeIndicationProxy.ifc);
   BlueScopeRequestWrapper blueScopeRequestWrapper <- mkBlueScopeRequestWrapper(1003,bs.requestIfc);

   MemcpyIndicationProxy memcpyIndicationProxy <- mkMemcpyIndicationProxy(7);
   MemcpyRequest memcpyRequest <- mkMemcpyRequest(memcpyIndicationProxy.ifc, dma_stream_read_chan.dmaServer,
						  dma_stream_write_chan.dmaServer, dma_word_read_chan.dmaServer, bs);
   MemcpyRequestWrapper memcpyRequestWrapper <- mkMemcpyRequestWrapper(1008,memcpyRequest);

   Vector#(6,StdPortal) portals;
   portals[0] = memcpyRequestWrapper.portalIfc;
   portals[1] = memcpyIndicationProxy.portalIfc;
   portals[2] = blueScopeRequestWrapper.portalIfc;
   portals[3] = blueScopeIndicationProxy.portalIfc;
   portals[4] = dmaRequestWrapper.portalIfc;
   portals[5] = dmaIndicationProxy.portalIfc;

   Directory dir <- mkDirectory(portals);
   Vector#(1,StdPortal) directories;
   directories[0] = dir.portalIfc;

   // when constructing ctrl and interrupt muxes, directories must be the first argument
   let ctrl_mux <- mkAxiSlaveMux(directories,portals);
   let interrupt_mux <- mkInterruptMux(portals);

   interface ReadOnly interrupt = interrupt_mux;
   interface StdAxi3Slave ctrl = ctrl_mux;
`ifndef BSIM
   interface Vector m_axi = replicate(dma.m_axi);
`endif
endmodule

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;

// for PCIE
import Connectable       :: *;
import Xilinx            :: *;
import XilinxPCIE        :: *;
import Xilinx7PcieBridge :: *;
import PcieToAxiBridge   :: *;

// portz libraries
import AxiClientServer::*;
import AxiMasterSlave::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import BlueScope::*;
import AxiRDMA::*;
import BsimRDMA::*;
import PortalMemory::*;
import PortalRMemory::*;

// generated by tool
import MemcpyRequestWrapper::*;
import BlueScopeRequestWrapper::*;
import DMARequestWrapper::*;
import MemcpyIndicationProxy::*;
import BlueScopeIndicationProxy::*;
import DMAIndicationProxy::*;

// defined by user
import Memcpy::*;

module mkPortalTop(StdPortalDmaTop);

   DMAIndicationProxy dmaIndicationProxy <- mkDMAIndicationProxy(9);
   // Max burst 16
   DMAReadBuffer#(64,8) dma_stream_read_chan <- mkDMAReadBuffer();

   // Max burst 16
   DMAWriteBuffer#(64,8) dma_stream_write_chan <- mkDMAWriteBuffer();

   // Max burst 1 because it only reads one word at a time
   DMAReadBuffer#(64,1) dma_word_read_chan <- mkDMAReadBuffer();

   // Max burst 16
   DMAWriteBuffer#(64,8) dma_debug_write_chan <- mkDMAWriteBuffer();

   Vector#(2,  DMAReadClient#(64))   readClients = newVector();
   readClients[0] = dma_stream_read_chan.dmaClient;
   readClients[1] = dma_word_read_chan.dmaClient;

   Vector#(2, DMAWriteClient#(64)) writeClients = newVector();
   writeClients[0] = dma_stream_write_chan.dmaClient;
   writeClients[1] = dma_debug_write_chan.dmaClient;

`ifdef BSIM
   BsimDMAServer#(64)     dma <- mkBsimDMAServer(dmaIndicationProxy.ifc, readClients, writeClients);
`else
   Integer               numRequests = 8;
   AxiDMAServer#(64,8)   dma <- mkAxiDMAServer(dmaIndicationProxy.ifc, numRequests, readClients, writeClients);
`endif

   DMARequestWrapper dmaRequestWrapper <- mkDMARequestWrapper(1005,dma.request);

   BlueScopeIndicationProxy blueScopeIndicationProxy <- mkBlueScopeIndicationProxy(8);
   BlueScope bs <- mkBlueScope(32, dma_debug_write_chan.dmaServer, blueScopeIndicationProxy.ifc);
   BlueScopeRequestWrapper blueScopeRequestWrapper <- mkBlueScopeRequestWrapper(1003,bs.requestIfc);

   MemcpyIndicationProxy memcpyIndicationProxy <- mkMemcpyIndicationProxy(7);
   MemcpyRequest memcpyRequest <- mkMemcpyRequest(memcpyIndicationProxy.ifc, dma_stream_read_chan.dmaServer,
						  dma_stream_write_chan.dmaServer, dma_word_read_chan.dmaServer, bs);
   MemcpyRequestWrapper memcpyRequestWrapper <- mkMemcpyRequestWrapper(1008,memcpyRequest);

   Vector#(6,StdPortal) portals;
   portals[0] = memcpyRequestWrapper.portalIfc;
   portals[1] = memcpyIndicationProxy.portalIfc;
   portals[2] = blueScopeRequestWrapper.portalIfc;
   portals[3] = blueScopeIndicationProxy.portalIfc;
   portals[4] = dmaRequestWrapper.portalIfc;
   portals[5] = dmaIndicationProxy.portalIfc;

   Directory dir <- mkDirectory(portals);
   Vector#(1,StdPortal) directories;
   directories[0] = dir.portalIfc;

   // when constructing ctrl and interrupt muxes, directories must be the first argument
   let ctrl_mux <- mkAxiSlaveMux(directories,portals);
   let interrupt_mux <- mkInterruptMux(portals);

   Vector#(1, StdAxi3Client) v_m_axi = replicate(dma.m_axi);

   interface ReadOnly interrupt = interrupt_mux;
   interface StdAxi3Slave ctrl = ctrl_mux;
`ifndef BSIM
   interface Vector m_axi = v_m_axi;
`endif
endmodule


simplify Bscan

simplify Bscan

// 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 Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

interface BscanBram#(type atype, type dtype);
   interface Clock jtagClock;
   interface Reset jtagReset;
   interface BRAMClient#(atype, dtype) bramClient;
endinterface

module mkBscanBram#(Integer bus, atype addr)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz), Add#(1, a__, dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   //Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);
   //SyncBitIfc#(Bit#(asz)) addr_jtag <- mkSyncBits(0, defaultClock, defaultReset, tck, rst);
   Wire#(Maybe#(BRAMRequest#(atype, dtype))) requestWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);
   Wire#(Maybe#(dtype)) responseWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(asz)) addrReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bool) capture_delay <- mkReg(False, clocked_by tck, reset_by rst);
   Reg#(Bool) selected_delay <- mkReg(False, clocked_by tck, reset_by rst);
   rule tdo;
       bscan.tdo(shiftReg[0]);
   endrule

   rule selected_rule;
       selected_delay <= bscan.sel() == 1;
       capture_delay <= bscan.sel() == 1 && bscan.capture() == 1;
   endrule

   //rule addr_clock_crossing;
       //addr_jtag.send(pack(addr));
   //endrule

   rule captureRule if (bscan.sel() == 1 && bscan.capture() == 1);
       requestWire <= tagged Valid BRAMRequest {write:False, responseOnWrite:False, address:unpack(addrReg), datain:?};
   endrule

   rule shiftrule if (bscan.sel() == 1 && bscan.shift() == 1);
       Bit#(dsz) shift = shiftReg;
       if (capture_delay) begin
	  Maybe#(dtype) m = responseWire;
	  let d = fromMaybe(unpack(0), m);
	  shift = pack(d);
       end
       shiftReg <= {bscan.tdi(), shift[dsz-1:1]};
   endrule

   rule updateRule if (bscan.sel() == 1 && bscan.update() == 1 && bscan.capture() == 0);
       requestWire <= tagged Valid (BRAMRequest {write:True, responseOnWrite:False, address:unpack(addrReg), datain:unpack(shiftReg)});
       let addr = addrReg + 1;
       if (!selected_delay)
	  addr = 0;  // first time USER1 selected, reset address
       addrReg <= addr;
   endrule

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (requestWire matches tagged Valid .req);
	    return req;
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
	    responseWire <= tagged Valid d;
	 endmethod
      endinterface
   endinterface
   interface Clock jtagClock = tck;
   interface Reset jtagReset = rst;
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 FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

interface Bscan#(numeric type width);
   interface Put#(Bit#(width)) capture;
   interface Get#(Bit#(width)) update;
endinterface

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

module mkBscan#(Integer bus)(Bscan#(width));
   let width = valueOf(width);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
       // SEL := (IR == 'USERx')
       // CAPTURE, RESET, RUNTEST, SHIFT, UPDATE: <name> := (TAP_state == <name>-DR)
       // TCK, TDI, TDO := corresponding JTAG pins
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);

   Reg#(Bit#(width)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   SyncFIFOIfc#(Bit#(width)) infifo <- mkSyncFIFO(2, defaultClock, defaultReset, tck);
   SyncFIFOIfc#(Bit#(width)) outfifo <- mkSyncFIFO(2, tck, rst, defaultClock);
   Wire#(Bit#(1)) tdow <- mkDWire(0, clocked_by tck, reset_by rst);
   rule tdo;
      bscan.tdo(tdow);
   endrule

   rule captureRule if (bscan.capture() == 1 && bscan.sel() == 1);
      if (infifo.notEmpty()) begin
	 infifo.deq();
      end
      //else
      //shiftReg <= 0;
   endrule
   rule shift if (bscan.shift() == 1 && bscan.sel() == 1);
      tdow <= shiftReg[0];
      let v = (shiftReg >> 1);
      v[width-1] = bscan.tdi();
      shiftReg <= v;
   endrule
   rule updateRule if (bscan.update() == 1 && bscan.sel() == 1);
      //if (outfifo.notFull()) begin
      //outfifo.enq(shiftReg);
      //end
   endrule

   interface Put capture = toPut(infifo);
   interface Get update = toGet(outfifo);
endmodule

interface BscanBram#(type atype, type dtype);
   interface Clock jtagClock;
   interface Reset jtagReset;
   interface BRAMClient#(atype, dtype) bramClient;
   method Bit#(4) debug;
endinterface

module mkBscanBram#(Integer bus, atype addr)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);
   SyncBitIfc#(Bit#(asz)) addr_jtag <- mkSyncBits(0, defaultClock, defaultReset, tck, rst);
   Wire#(Maybe#(BRAMRequest#(atype, dtype))) requestWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);
   Wire#(Maybe#(dtype)) responseWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(asz)) addrReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bool) capture_delay <- mkReg(False, clocked_by tck, reset_by rst);
   Reg#(Bool) selected_delay <- mkReg(False, clocked_by tck, reset_by rst);
   Wire#(Bit#(1)) tdow <- mkDWire(0, clocked_by tck, reset_by rst);
   rule tdo;
      bscan.tdo(tdow);
   endrule

   rule selected_rule;
       selected_delay <= bscan.sel() == 1;
       capture_delay <= bscan.sel() == 1 && bscan.capture() == 1;
   endrule

   rule addr_clock_crossing;
       addr_jtag.send(pack(addr));
   endrule

   rule captureRule if (bscan.sel() == 1 && bscan.capture() == 1);
       requestWire <= tagged Valid BRAMRequest {write:False, responseOnWrite:False, address:unpack(addrReg), datain:?};
   endrule

   rule shiftrule if (bscan.sel() == 1 && bscan.shift() == 1);
       Bit#(dsz) shift = shiftReg;
       if (capture_delay) begin
	  Maybe#(dtype) m = responseWire;
	  let d = fromMaybe(unpack(0), m);
	  shift = pack(d);
       end
       tdow <= shift[0];
       let v = (shift >> 1);
       v[dsz-1] = bscan.tdi();
       shiftReg <= v;
   endrule

   rule updateRule if (bscan.sel() == 1 && bscan.update() == 1 && bscan.capture() == 0);
       requestWire <= tagged Valid (BRAMRequest {write:True, responseOnWrite:False, address:unpack(addrReg), datain:unpack(shiftReg)});
       let addr = addrReg + 1;
       if (!selected_delay)
	  addr = 0;  // first time USER1 selected, reset address
       addrReg <= addr;
   endrule

   method Bit#(4) debug;
       return {bscan.sel(), bscan.capture(), bscan.shift(), bscan.update()};
   endmethod
   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (requestWire matches tagged Valid .req);
	    return req;
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
	    responseWire <= tagged Valid d;
	 endmethod
      endinterface
   endinterface
   interface Clock jtagClock = tck;
   interface Reset jtagReset = rst;
endmodule


disable multiple VLANs

disable multiple VLANs

// Copyright (c) 2015 Cornell University.

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

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

import BuildVector::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import Pipe::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;

import Ethernet::*;
import P4Types::*;

interface Parser;
   // derive parseReset from start of packet
   method Action parserReset();
   interface PipeIn#(EtherData) frameIn;
   interface PipeOut#(void) parseDone;
   interface PipeOut#(MatchKey_port_mapping) match_key_port_mapping;
   interface PipeOut#(MatchKey_bd) match_key_bd;
   interface PipeOut#(MatchKey_ipv4_fib) match_key_ipv4_fib;
   interface PipeOut#(MatchKey_ipv4_fib_lpm) match_key_ipv4_fib_lpm;
   interface PipeOut#(MatchKey_nexthop) match_key_nexthop;
   interface PipeOut#(MatchKey_rewrite_mac) match_rewrite_mac;
   interface PipeOut#(Bit#(128)) payloadOut;
endinterface

interface ParseEthernet;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeOut#(Ethernet_t) parsedOut;
   interface PipeOut#(Bit#(16)) unparsedOutIpv4; // number is parse state id
   interface PipeOut#(Bit#(16)) unparsedOutVlan; // number is parse state id
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseVlan;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Vlan_tag_t) parsedOut;
   interface PipeOut#(Bit#(112)) unparsedOutVlan0;
   interface PipeOut#(Bit#(80)) unparsedOutVlan1;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseIpv4;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Ipv4_t) parsedOut;
   interface PipeIn#(Bit#(112)) unparsedInVlan0;
   interface PipeIn#(Bit#(80)) unparsedInVlan1;
   interface PipeOut#(Bit#(112)) unparsedOut;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

typedef enum {S0, S1, S2, S3, S4} ParserState deriving (Bits, Eq);
instance FShow#(ParserState);
   function Fmt fshow (ParserState state);
      return $format(" State %x", state);
   endfunction
endinstance

module mkParseEthernet(ParseEthernet);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Ethernet_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_ipv4_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_vlan_fifo <- mkSizedFIFOF(1);
   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule cycleRule if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
   endrule

   Stmt parse_ethernet =
   seq
   action // parse_ethernet
      let data = packet_in_wire;
      Vector#(128, Bit#(1)) dataVec = unpack(data);
      let ethernet = extrace_ethernet(pack(takeAt(0, dataVec)));
      Vector#(16, Bit#(1)) unparsed = takeAt(112, dataVec);
      if (verbose) $display(fshow(cycle)
                            +fshow(" ether.dstAddr=")+fshow(ethernet.dstAddr)
                            +fshow(" ether.srcAddr=")+fshow(ethernet.srcAddr)
                            +fshow(" ether.etherType=")+fshow(ethernet.etherType));

      ParserState nextState = S0;
      case (byteSwap2B(ethernet.etherType)) matches
         'h_8100: begin
            unparsed_out_parse_vlan_fifo.enq(pack(unparsed));
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            unparsed_out_parse_ipv4_fifo.enq(pack(unparsed));
            nextState = S3;
         end
         default: begin
            $display("null");
         end
      endcase
      next_state_fifo.enq(nextState);
   endaction
   endseq;

   FSM fsm_parse_ethernet <- mkFSM(parse_ethernet);

   method Action start();
      fsm_parse_ethernet.start;
   endmethod
   method Action clear();
      fsm_parse_ethernet.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedOutIpv4 = toPipeOut(unparsed_out_parse_ipv4_fifo);
   interface unparsedOutVlan = toPipeOut(unparsed_out_parse_vlan_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseVlanArbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(2, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseVlanArbiter(ParseVlanArbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(2, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<2; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

// Parse second VLAN
module mkParseVlan(ParseVlan);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan0 <- mkBypassFIFOF;
//   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan1 <- mkBypassFIFOF;
   FIFOF#(Vlan_tag_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(112)) unparsed_out_parse_vlan0_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(80)) unparsed_out_parse_vlan1_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseVlanArbiter nextStateArbiter <- mkParseVlanArbiter();

   function ParserState compute_next_state(Bit#(16) etherType);
      ParserState nextState = S0;
      case (byteSwap2B(etherType)) matches
         'h_8100: begin
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            nextState = S3;
         end
      endcase
      return nextState;
   endfunction

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      if (verbose) $display(fshow(cycle) + fshow("load packet in"));
   endrule

   rule load_unparsed_in;
      let data_delayed <- toGet(unparsed_in_fifo).get;
      unparsed_in_fifo_vlan0.enq(data_delayed);
//      unparsed_in_fifo_vlan1.enq(data_delayed);
      if (verbose) $display(fshow(cycle) + fshow("load unparsed in"));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_vlan_0 =
   // VLAN
   seq
   action
      let data_delayed <- toGet(unparsed_in_fifo_vlan0).get;
      let data_current = packet_in_wire;
      $display("VLAN %x", data_current);
      Bit#(144) data = {data_current, data_delayed};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
      let nextState0 = compute_next_state(vlan0.etherType);
      let residue0 = takeAt(32, dataVec);
      if (nextState0 == S3) begin
         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
         unparsed_out_parse_vlan0_fifo.enq(pack(residue0));
         nextStateArbiter.in[0].enq(nextState0);
      end
   endaction
   endseq;

//   Stmt parse_vlan_1 =
//   // VLAN|VLAN
//   seq
//   action
//      let data_delayed <- toGet(unparsed_in_fifo_vlan1).get;
//      let data_current = packet_in_wire;
//      $display("VLAN|VLAN %x", data_current);
//      Bit#(144) data = {data_current, data_delayed};
//      Vector#(144, Bit#(1)) dataVec = unpack(data);
//      let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
//      let nextState0 = compute_next_state(vlan0.etherType);
//      let residue0 = takeAt(32, dataVec);
//      let vlan1 = extract_vlan(pack(takeAt(32, dataVec)));
//      let nextState1 = compute_next_state(vlan1.etherType);
//      let residue1 = takeAt(64, dataVec);
//      if (nextState0 == S2 && nextState1 == S3) begin
//         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
//         if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan1.etherType));
//         unparsed_out_parse_vlan1_fifo.enq(pack(residue1));
//         nextStateArbiter.in[1].enq(nextState1);
//      end
//   endaction
//   endseq;

   FSM fsm_parse_vlan_0 <- mkFSM(parse_vlan_0);
//   FSM fsm_parse_vlan_1 <- mkFSM(parse_vlan_0);

   method Action start;
      fsm_parse_vlan_0.start;
//      fsm_parse_vlan_1.start;
   endmethod
   method Action clear;
      fsm_parse_vlan_0.abort;
//      fsm_parse_vlan_1.abort;
   endmethod

   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedOutVlan0 = toPipeOut(unparsed_out_parse_vlan0_fifo);
//   interface unparsedOutVlan1 = toPipeOut(unparsed_out_parse_vlan1_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseIpv4Arbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(3, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseIpv4Arbiter(ParseIpv4Arbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(3, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<3; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

module mkParseIpv4(ParseIpv4);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;

   FIFOF#(Ipv4_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_in_vlan0_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(80)) unparsed_in_vlan1_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(144)) internal_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseIpv4Arbiter nextStateArbiter <- mkParseIpv4Arbiter();

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      $display(fshow("loading packet") + fshow(data_current));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_ipv4_0 =
   // IP
   seq
   action // parse_ipv4
      let residue_last <- toGet(unparsed_in_fifo).get; // 16-bit
      let data_current = packet_in_wire;
      Bit#(144) data = {data_current, residue_last};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      internal_fifo.enq(data);
      if (verbose) $display(fshow(cycle) + fshow("wait one cycle!"));
   endaction
   action // parse_ipv4 0
      let data_delayed <- toGet(internal_fifo).get;
      let data_current = packet_in_wire;
      Bit#(272) data = {data_current, data_delayed};
      Vector#(272, Bit#(1)) dataVec = unpack(data);
      Vector#(112, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[0].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_1 =
   // VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan0_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(240) data = {data_current, residue_last};
      Vector#(240, Bit#(1)) dataVec = unpack(data);
      Vector#(80, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[1].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_2 =
   // VLAN|VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan1_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(208) data = {data_current, residue_last};
      Vector#(208, Bit#(1)) dataVec = unpack(data);
      Vector#(48, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[2].enq(S4);
   endaction
   endseq;

   FSM fsm_parse_ipv4_0 <- mkFSM(parse_ipv4_0);
   FSM fsm_parse_ipv4_1 <- mkFSM(parse_ipv4_1);
   FSM fsm_parse_ipv4_2 <- mkFSM(parse_ipv4_2);

   method Action start();
      fsm_parse_ipv4_0.start;
      fsm_parse_ipv4_1.start;
      fsm_parse_ipv4_2.start;
   endmethod
   method Action clear();
      fsm_parse_ipv4_0.abort;
      fsm_parse_ipv4_1.abort;
      fsm_parse_ipv4_2.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedInVlan0 = toPipeIn(unparsed_in_vlan0_fifo);
   interface unparsedInVlan1 = toPipeIn(unparsed_in_vlan1_fifo);
   interface unparsedOut = toPipeOut(unparsed_out_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

(* synthesize *)
module mkParser(Parser);
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(void) parse_done_fifo <- mkSizedFIFOF(1);

   ParseEthernet parse_ethernet <- mkParseEthernet();
   ParseVlan parse_vlan <- mkParseVlan();
   ParseIpv4 parse_ipv4 <- mkParseIpv4();

   List#(Reg#(Vlan_tag_t)) vlan_tag_stack <- List::replicateM(2, mkReg(defaultValue));

   mkConnection(parse_ethernet.unparsedOutIpv4, parse_ipv4.unparsedIn);
   mkConnection(parse_ethernet.unparsedOutVlan, parse_vlan.unparsedIn);
   mkConnection(parse_vlan.unparsedOutVlan0, parse_ipv4.unparsedInVlan0);
   mkConnection(parse_vlan.unparsedOutVlan1, parse_ipv4.unparsedInVlan1);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Reg#(ParserState) curr_state <- mkReg(S0);
   Reg#(Bool) started <- mkReg(False);

   rule start_fsm (curr_state == S0 && data_in_fifo.notEmpty);
      if (!started) begin
         parse_ethernet.start;
         parse_vlan.start;
         parse_ipv4.start;
         started <= True;
      end
   endrule

   rule stop_fsm (curr_state == S4);
      if (started) begin
         parse_ethernet.clear;
         parse_ipv4.clear;
         parse_vlan.clear;
         started <= False;
      end
   endrule

   // Parsing Graph
   (* fire_when_enabled *)
   rule state_S0 (curr_state == S0 && data_in_fifo.notEmpty);
      let v = data_in_fifo.first;
      if (v.sop) begin
         curr_state <= S1;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
      else begin
         data_in_fifo.deq;
      end
   endrule
   (* fire_when_enabled *)
   rule state_S1 (curr_state == S1);
      let v <- toGet(parse_ethernet.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S2 (curr_state == S2);
      let v <- toGet(parse_vlan.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S3 (curr_state == S3);
      let v <- toGet(parse_ipv4.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S4 (curr_state == S4);
      let v <- toGet(data_in_fifo).get;
      if (v.eop) begin
         curr_state <= S0;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
   endrule

   // Data dispatcher.
   rule state_S1_input (curr_state == S1);
      let v <- toGet(data_in_fifo).get;
      parse_ethernet.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ethernet enqueue ")+ fshow(v));
   endrule
   rule state_S2_input (curr_state == S2);
      let v <- toGet(data_in_fifo).get;
      parse_vlan.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_vlan enqueue ")+ fshow(v));
   endrule
   rule state_S3_input (curr_state == S3);
      let v <- toGet(data_in_fifo).get;
      parse_ipv4.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ipv4 enqueue ") + fshow(v));
   endrule

   // derive parse done from state machine
   interface frameIn = toPipeIn(data_in_fifo);
   interface parseDone = toPipeOut(parse_done_fifo);
endmodule

// Copyright (c) 2015 Cornell University.

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

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

import BuildVector::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import Pipe::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;

import Ethernet::*;
import P4Types::*;

interface Parser;
   // derive parseReset from start of packet
   method Action parserReset();
   interface PipeIn#(EtherData) frameIn;
   interface PipeOut#(void) parseDone;
   interface PipeOut#(MatchKey_port_mapping) match_key_port_mapping;
   interface PipeOut#(MatchKey_bd) match_key_bd;
   interface PipeOut#(MatchKey_ipv4_fib) match_key_ipv4_fib;
   interface PipeOut#(MatchKey_ipv4_fib_lpm) match_key_ipv4_fib_lpm;
   interface PipeOut#(MatchKey_nexthop) match_key_nexthop;
   interface PipeOut#(MatchKey_rewrite_mac) match_rewrite_mac;
   interface PipeOut#(Bit#(128)) payloadOut;
endinterface

interface ParseEthernet;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeOut#(Ethernet_t) parsedOut;
   interface PipeOut#(Bit#(16)) unparsedOutIpv4; // number is parse state id
   interface PipeOut#(Bit#(16)) unparsedOutVlan; // number is parse state id
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseVlan;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Vlan_tag_t) parsedOut;
   interface PipeOut#(Bit#(112)) unparsedOutVlan0;
   interface PipeOut#(Bit#(80)) unparsedOutVlan1;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

interface ParseIpv4;
   interface PipeIn#(Bit#(128)) packetIn;
   interface PipeIn#(Bit#(16)) unparsedIn;
   interface PipeOut#(Ipv4_t) parsedOut;
   interface PipeIn#(Bit#(112)) unparsedInVlan0;
   interface PipeIn#(Bit#(80)) unparsedInVlan1;
   interface PipeOut#(Bit#(112)) unparsedOut;
   interface PipeOut#(ParserState) nextState;
   method Action start;
   method Action clear;
endinterface

typedef enum {S0, S1, S2, S3, S4} ParserState deriving (Bits, Eq);
instance FShow#(ParserState);
   function Fmt fshow (ParserState state);
      return $format(" State %x", state);
   endfunction
endinstance

module mkParseEthernet(ParseEthernet);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Ethernet_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_ipv4_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16))  unparsed_out_parse_vlan_fifo <- mkSizedFIFOF(1);
   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule cycleRule if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
   endrule

   Stmt parse_ethernet =
   seq
   action // parse_ethernet
      //let data <- toGet(packet_in_fifo).get;
      let data = packet_in_wire;
      Vector#(128, Bit#(1)) dataVec = unpack(data);
      let ethernet = extrace_ethernet(pack(takeAt(0, dataVec)));
      Vector#(16, Bit#(1)) unparsed = takeAt(112, dataVec);
      if (verbose) $display(fshow(cycle)
                            +fshow(" ether.dstAddr=")+fshow(ethernet.dstAddr)
                            +fshow(" ether.srcAddr=")+fshow(ethernet.srcAddr)
                            +fshow(" ether.etherType=")+fshow(ethernet.etherType));

      ParserState nextState = S0;
      case (byteSwap2B(ethernet.etherType)) matches
         'h_8100: begin
            unparsed_out_parse_vlan_fifo.enq(pack(unparsed));
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            unparsed_out_parse_ipv4_fifo.enq(pack(unparsed));
            nextState = S3;
         end
         default: begin
            $display("null");
         end
      endcase
      next_state_fifo.enq(nextState);
   endaction
   endseq;

   FSM fsm_parse_ethernet <- mkFSMWithPred(parse_ethernet, True);
   //Once once_parse_ethernet <- mkOnce(fsm_parse_ethernet.start);

   //method Action start = once_parse_ethernet.start;
   method Action start = fsm_parse_ethernet.start;
   method Action clear();
      //once_parse_ethernet.clear;
      fsm_parse_ethernet.abort;
      //packet_in_fifo.clear;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedOutIpv4 = toPipeOut(unparsed_out_parse_ipv4_fifo);
   interface unparsedOutVlan = toPipeOut(unparsed_out_parse_vlan_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseVlanArbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(2, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseVlanArbiter(ParseVlanArbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(2, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<2; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

// Parse second VLAN
module mkParseVlan(ParseVlan);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan0 <- mkBypassFIFOF;
   FIFOF#(Bit#(16)) unparsed_in_fifo_vlan1 <- mkBypassFIFOF;
   FIFOF#(Vlan_tag_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(112)) unparsed_out_parse_vlan0_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(80)) unparsed_out_parse_vlan1_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseVlanArbiter nextStateArbiter <- mkParseVlanArbiter();

   function ParserState compute_next_state(Bit#(16) etherType);
      ParserState nextState = S0;
      case (byteSwap2B(etherType)) matches
         'h_8100: begin
            nextState = S2;
         end
         'h_9100: begin
            nextState = S2;
         end
         'h_0800: begin
            nextState = S3;
         end
      endcase
      return nextState;
   endfunction

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      if (verbose) $display(fshow(cycle) + fshow("load packet in"));
   endrule

   rule load_unparsed_in;
      let data_delayed <- toGet(unparsed_in_fifo).get;
      unparsed_in_fifo_vlan0.enq(data_delayed);
      unparsed_in_fifo_vlan1.enq(data_delayed);
      if (verbose) $display(fshow(cycle) + fshow("load unparsed in"));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_vlan =
   par
      // VLAN
      seq
      action
         let data_delayed <- toGet(unparsed_in_fifo_vlan0).get;
         let data_current = packet_in_wire;
         $display("VLAN %x", data_current);
         Bit#(144) data = {data_current, data_delayed};
         Vector#(144, Bit#(1)) dataVec = unpack(data);
         let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
         let nextState0 = compute_next_state(vlan0.etherType);
         let residue0 = takeAt(32, dataVec);
         if (nextState0 == S3) begin
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
            unparsed_out_parse_vlan0_fifo.enq(pack(residue0));
            nextStateArbiter.in[0].enq(nextState0);
         end
      endaction
      endseq
      // VLAN|VLAN
      seq
      action
         let data_delayed <- toGet(unparsed_in_fifo_vlan1).get;
         let data_current = packet_in_wire;
         $display("VLAN|VLAN %x", data_current);
         Bit#(144) data = {data_current, data_delayed};
         Vector#(144, Bit#(1)) dataVec = unpack(data);
         let vlan0 = extract_vlan(pack(takeAt(0, dataVec)));
         let nextState0 = compute_next_state(vlan0.etherType);
         let residue0 = takeAt(32, dataVec);
         let vlan1 = extract_vlan(pack(takeAt(32, dataVec)));
         let nextState1 = compute_next_state(vlan1.etherType);
         let residue1 = takeAt(64, dataVec);
         if (nextState0 == S2 && nextState1 == S3) begin
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan0.etherType));
            if (verbose) $display(fshow(cycle) + fshow("Vlan etherType=") + fshow(vlan1.etherType));
            unparsed_out_parse_vlan1_fifo.enq(pack(residue1));
            nextStateArbiter.in[1].enq(nextState1);
         end
      endaction
      endseq
   endpar;

   FSM fsm_parse_vlan <- mkFSMWithPred(parse_vlan, True);
   //Once once_parse_vlan <- mkOnce(fsm_parse_vlan.start);

   //method Action start = once_parse_vlan.start;
   method Action start = fsm_parse_vlan.start;
   method Action clear;
      //once_parse_vlan.clear;
      fsm_parse_vlan.abort;
      //packet_in_fifo.clear;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedOutVlan0 = toPipeOut(unparsed_out_parse_vlan0_fifo);
   interface unparsedOutVlan1 = toPipeOut(unparsed_out_parse_vlan1_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

interface ParseIpv4Arbiter;
   interface PipeOut#(ParserState) outToFSM;
   interface Vector#(3, PipeIn#(ParserState)) in;
endinterface

(* synthesize *)
module mkParseIpv4Arbiter(ParseIpv4Arbiter);
   FIFOF#(ParserState) state_out_fifo <- mkBypassFIFOF;
   Vector#(3, FIFOF#(ParserState)) state_in_fifo <- replicateM(mkBypassFIFOF);

   (* fire_when_enabled *)
   rule arbitrate_outgoing_state;
      Bool stateSet = False;
      for (Integer port=0; port<3; port=port+1) begin
         if (!stateSet && state_in_fifo[port].notEmpty()) begin
            ParserState state <- toGet(state_in_fifo[port]).get;
            stateSet = True;
            state_out_fifo.enq(state);
         end
      end
   endrule
   interface in = map(toPipeIn, state_in_fifo);
   interface outToFSM = toPipeOut(state_out_fifo);
endmodule

module mkParseIpv4(ParseIpv4);
   FIFOF#(Bit#(128)) packet_in_fifo <- mkBypassFIFOF;

   FIFOF#(Ipv4_t) parsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(16)) unparsed_in_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_in_vlan0_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(80)) unparsed_in_vlan1_fifo <- mkBypassFIFOF;
   FIFOF#(Bit#(112)) unparsed_out_fifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(144)) internal_fifo <- mkSizedFIFOF(1);

   FIFOF#(ParserState) next_state_fifo <- mkBypassFIFOF;
   Wire#(Bit#(128)) packet_in_wire <- mkDWire(0);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   ParseIpv4Arbiter nextStateArbiter <- mkParseIpv4Arbiter();

   rule load_packet_in;
      let data_current <- toGet(packet_in_fifo).get;
      packet_in_wire <= data_current;
      $display(fshow("loading packet") + fshow(data_current));
   endrule

   mkConnection(nextStateArbiter.outToFSM, toPipeIn(next_state_fifo));

   Stmt parse_ipv4_0 =
   // IP
   seq
   action // parse_ipv4
      let residue_last <- toGet(unparsed_in_fifo).get; // 16-bit
      let data_current = packet_in_wire;
      Bit#(144) data = {data_current, residue_last};
      Vector#(144, Bit#(1)) dataVec = unpack(data);
      internal_fifo.enq(data);
      if (verbose) $display(fshow(cycle) + fshow("wait one cycle!"));
   endaction
   action // parse_ipv4 0
      let data_delayed <- toGet(internal_fifo).get;
      let data_current = packet_in_wire;
      Bit#(272) data = {data_current, data_delayed};
      Vector#(272, Bit#(1)) dataVec = unpack(data);
      Vector#(112, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[0].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_1 =
   // VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan0_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(240) data = {data_current, residue_last};
      Vector#(240, Bit#(1)) dataVec = unpack(data);
      Vector#(80, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[1].enq(S4);
   endaction
   endseq;

   Stmt parse_ipv4_2 =
   // VLAN|VLAN|IP
   seq
   action
      let residue_last <- toGet(unparsed_in_vlan1_fifo).get; // 112-bit;
      let data_current = packet_in_wire;
      Bit#(208) data = {data_current, residue_last};
      Vector#(208, Bit#(1)) dataVec = unpack(data);
      Vector#(48, Bit#(1)) residue = takeAt(160, dataVec);
      let ipv4 = extract_ipv4(data[159:0]);
      if (verbose) $display(fshow(cycle)+
                            $format(" ipv4.srcAddr=%x", ipv4.srcAddr)+
                            $format(" ipv4.dstAddr=%x", ipv4.dstAddr));
      nextStateArbiter.in[2].enq(S4);
   endaction
   endseq;

   FSM fsm_parse_ipv4_0 <- mkFSMWithPred(parse_ipv4_0, True);
   FSM fsm_parse_ipv4_1 <- mkFSMWithPred(parse_ipv4_1, True);
   FSM fsm_parse_ipv4_2 <- mkFSMWithPred(parse_ipv4_2, True);

   method Action start();
      fsm_parse_ipv4_0.start;
      fsm_parse_ipv4_1.start;
      fsm_parse_ipv4_2.start;
   endmethod
   method Action clear();
      fsm_parse_ipv4_0.abort;
      fsm_parse_ipv4_1.abort;
      fsm_parse_ipv4_2.abort;
   endmethod
   interface packetIn = toPipeIn(packet_in_fifo);
   interface unparsedIn = toPipeIn(unparsed_in_fifo);
   interface unparsedInVlan0 = toPipeIn(unparsed_in_vlan0_fifo);
   interface unparsedInVlan1 = toPipeIn(unparsed_in_vlan1_fifo);
   interface unparsedOut = toPipeOut(unparsed_out_fifo);
   interface parsedOut = toPipeOut(parsed_out_fifo);
   interface nextState = toPipeOut(next_state_fifo);
endmodule

(* synthesize *)
module mkParser(Parser);
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(void) parse_done_fifo <- mkSizedFIFOF(1);

   ParseEthernet parse_ethernet <- mkParseEthernet();
   ParseVlan parse_vlan <- mkParseVlan();
   ParseIpv4 parse_ipv4 <- mkParseIpv4();

   List#(Reg#(Vlan_tag_t)) vlan_tag_stack <- List::replicateM(2, mkReg(defaultValue));

   mkConnection(parse_ethernet.unparsedOutIpv4, parse_ipv4.unparsedIn);
   mkConnection(parse_ethernet.unparsedOutVlan, parse_vlan.unparsedIn);
   mkConnection(parse_vlan.unparsedOutVlan0, parse_ipv4.unparsedInVlan0);
   mkConnection(parse_vlan.unparsedOutVlan1, parse_ipv4.unparsedInVlan1);

   let verbose = True;
   Reg#(Cycle_t) cycle <- mkReg(defaultValue);
   rule every if (verbose);
      cycle.cnt <= cycle.cnt + 1;
   endrule

   Reg#(ParserState) curr_state <- mkReg(S0);
   Reg#(Bool) started <- mkReg(False);

   rule start_fsm (curr_state == S0 && data_in_fifo.notEmpty);
      //$display(fshow(cycle) + fshow("started"));
      if (!started) begin
         parse_ethernet.start;
         parse_vlan.start;
         parse_ipv4.start;
         started <= True;
      end
   endrule

   rule stop_fsm (curr_state == S4);
      //$display(fshow(cycle) + fshow("end"));
      if (started) begin
         parse_ethernet.clear;
         parse_ipv4.clear;
         parse_vlan.clear;
         started <= False;
      end
   endrule

   // Parsing Graph
   (* fire_when_enabled *)
   rule state_S0 (curr_state == S0 && data_in_fifo.notEmpty);
      let v = data_in_fifo.first;
      if (v.sop) begin
         curr_state <= S1;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
      else begin
         data_in_fifo.deq;
      end
   endrule
   (* fire_when_enabled *)
   rule state_S1 (curr_state == S1);
      let v <- toGet(parse_ethernet.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S2 (curr_state == S2);
      let v <- toGet(parse_vlan.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S3 (curr_state == S3);
      let v <- toGet(parse_ipv4.nextState).get;
      curr_state <= v;
      if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
   endrule
   (* fire_when_enabled *)
   rule state_S4 (curr_state == S4);
      let v <- toGet(data_in_fifo).get;
      if (v.eop) begin
         curr_state <= S0;
         if (verbose) $display(fshow(cycle) + fshow("Done with") + fshow(curr_state));
      end
   endrule

   // Data dispatcher.
   rule state_S1_input (curr_state == S1);
      let v <- toGet(data_in_fifo).get;
      parse_ethernet.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ethernet enqueue ")+ fshow(v));
   endrule
   rule state_S2_input (curr_state == S2);
      let v <- toGet(data_in_fifo).get;
      parse_vlan.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_vlan enqueue ")+ fshow(v));
   endrule
   rule state_S3_input (curr_state == S3);
      let v <- toGet(data_in_fifo).get;
      parse_ipv4.packetIn.enq(v.data);
      if (verbose) $display(fshow(cycle) + fshow("parse_ipv4 enqueue ") + fshow(v));
   endrule

   // derive parse done from state machine
   interface frameIn = toPipeIn(data_in_fifo);
   interface parseDone = toPipeOut(parse_done_fifo);
endmodule


add comments about SGList processing

add comments about SGList processing

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

// BSV Libraries
import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import MemTypes::*;
import StmtFSM::*;
import ClientServer::*;
import PortalMemory::*;

typedef 32 MaxNumSGLists;
typedef Bit#(TLog#(MaxNumSGLists)) SGListId;
typedef 12 SGListPageShift0;
typedef 16 SGListPageShift4;
typedef 20 SGListPageShift8;
typedef Bit#(TLog#(MaxNumSGLists)) RegionsIdx;

typedef 8 IndexWidth;

typedef struct {
   SGListId               id;
   Bit#(ObjectOffsetSize) off;
} ReqTup deriving (Eq,Bits,FShow);

`ifdef BSIM
`ifndef PCIE
import "BDPI" function ActionValue#(Bit#(32)) pareff(Bit#(32) handle, Bit#(32) size);
`endif
`endif

interface SGListMMU#(numeric type addrWidth);
   interface SGListSetup setup;
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef struct {
   Bit#(2) pageSize;
   Bit#(SGListPageShift8) value;
} Offset deriving (Eq,Bits,FShow);

typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift0)) Page;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) Page4;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) Page8;

typedef struct {
   Bit#(28) barrier;
   Bit#(IndexWidth) idxOffset;
   } SingleRegion deriving (Eq,Bits,FShow);

typedef struct {
   SingleRegion reg8;
   SingleRegion reg4;
   SingleRegion reg0;
   } Region deriving (Eq,Bits,FShow);

typedef struct {DmaErrorType errorType;
		Bit#(32) pref; } DmaError deriving (Bits);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

   // stage 0 (latency == 1)
   Vector#(2, FIFO#(ReqTup)) incomingReqs <- replicateM(mkFIFO);

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Region)       regall <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(ReqTup))           reqs0 <- replicateM(mkSizedFIFOF(3));

   // stage 2 (latency == 1)
   Vector#(2,FIFOF#(Tuple3#(Bool,Bool,Bool))) conds <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Tuple3#(Bit#(IndexWidth),Bit#(IndexWidth),Bit#(IndexWidth)))) idxOffsets0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(ReqTup))           reqs1 <- replicateM(mkSizedFIFOF(3));

   // stage 3 (latency == 1)
   Vector#(2,FIFOF#(Offset))           offs0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))    idxOffsets1 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))         ptrs1 <- replicateM(mkFIFOF);

   // stage 4 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page) pages <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(Offset))           offs1 <- replicateM(mkSizedFIFOF(3));

   // stage 4 (latnecy == 1)
   Vector#(2,FIFOF#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFOF);

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, -1, 0);
   endrule

   let page_shift0 = fromInteger(valueOf(SGListPageShift0));
   let page_shift4 = fromInteger(valueOf(SGListPageShift4));
   let page_shift8 = fromInteger(valueOf(SGListPageShift8));

   function BRAMServer#(a,b) portsel(BRAM2Port#(a,b) x, Integer i);
      if(i==0) return x.portA;
      else return x.portB;
   endfunction

   for (Integer i = 0; i < 2; i=i+1)
      rule stage1;  // first read in the address cutoff values between regions
	 ReqTup req <- toGet(incomingReqs[i]).get();
	 portsel(regall, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(req.id), datain:?});
	 reqs0[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2; // Now compare address cutoffs with requested offset
	 ReqTup req <- toGet(reqs0[i]).get;
	 Region regionall <- portsel(regall,i).response.get;

         Page off = truncate(req.off >> valueOf(SGListPageShift0));
         Page4 off4 = truncate(req.off >> valueOf(SGListPageShift4));
         Page4 off8 = truncate(req.off >> valueOf(SGListPageShift8));
	 let cond8 = off8 < truncate(regionall.reg8.barrier);
	 let cond4 = off4 < truncate(regionall.reg4.barrier);
	 let cond0 = off < regionall.reg0.barrier;

	 conds[i].enq(tuple3(cond8,cond4,cond0));
	 idxOffsets0[i].enq(tuple3(regionall.reg8.idxOffset,regionall.reg4.idxOffset, regionall.reg0.idxOffset));
	 reqs1[i].enq(req);
      endrule
      rule stage3; // Based on results of comparision, select a region, putting it into 'o.pageSize'.  idxOffset holds offset in sglist table of relevant entry
	 ReqTup req <- toGet(reqs1[i]).get;
	 Offset o = Offset{pageSize: 0, value: truncate(req.off)};
	 Bit#(IndexWidth) pbase = 0;
	 Bit#(IndexWidth) idxOffset = 0;

	 match{.cond8,.cond4,.cond0} <- toGet(conds[i]).get;
	 match{.idxOffset8,.idxOffset4,.idxOffset0} <- toGet(idxOffsets0[i]).get;

	 if (cond8) begin
	    //$display("request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 3;
	    pbase = truncate(req.off>>page_shift8);
	    idxOffset = idxOffset8;
	 end
	 else if (cond4) begin
	    //$display("request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 2;
	    pbase = truncate(req.off>>page_shift4);
	    idxOffset = idxOffset4;
	 end
	 else if (cond0) begin
	    //$display("request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 1;
	    pbase = truncate(req.off>>page_shift0);
	    idxOffset = idxOffset0;
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets1[i].enq(idxOffset);
	 ptrs1[i].enq(req.id);
      endrule
      rule stage4; // Read relevant sglist entry
	 let off <- toGet(offs0[i]).get();
	 let pbase <- toGet(pbases[i]).get();
	 let idxOffset <- toGet(idxOffsets1[i]).get();
	 let ptr <- toGet(ptrs1[i]).get();
	 Bit#(IndexWidth) p = pbase + idxOffset;
	 if (off.pageSize == 0) begin
	    //FIXME offset
	    //$display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadAddrTrans, pref: extend(ptr) });
	 end
	 //$display("p ages[%d].read %h", i, rp[i].first());
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:{ptr,p}, datain:?});
	 offs1[i].enq(off);
      endrule
      rule stage5; // Concatenate page base address from sglist entry with LSB offset bits from request and return
	 Page page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 //$display("p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(ObjectOffsetSize) rv = ?;
	 Page4 b4 = truncate(page);
	 Page8 b8 = truncate(page);
	 case (offset.pageSize)
	    1: rv = {page,truncate(offset.value)};
	    2: rv = {b4,truncate(offset.value)};
	    3: rv = {b8,truncate(offset.value)};
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   FIFO#(SGListId) configRespFifo <- mkFIFO;
   rule sendConfigResp;
      let ptr <- toGet(configRespFifo).get();
      dmaIndication.configResp(extend(ptr));
   endrule

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		incomingReqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   // FIXME: split this into three methods?
   interface SGListSetup setup;
   method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(32) index8, Bit#(64) barr4, Bit#(32) index4, Bit#(64) barr0, Bit#(32) index0);
      portsel(regall, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(pointer), datain: Region{
             reg8: SingleRegion{barrier: truncate(barr8), idxOffset: truncate(index8)},
             reg4: SingleRegion{barrier: truncate(barr4), idxOffset: truncate(index4)},
             reg0: SingleRegion{barrier: truncate(barr0), idxOffset: truncate(index0)}} });
      //$display("region pointer=%d off8=%h off4=%h off0=%h", pointer, off8, off4, off0);
      configRespFifo.enq(truncate(pointer));
   endmethod

   method Action sglist(Bit#(32) pointer, Bit#(32) pointerIndex, Bit#(64) addr,  Bit#(32) len);
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pointer, len);
`endif
`endif
         Bit#(IndexWidth) ind = truncate(pointerIndex);
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(pointer),ind}, datain:truncate(addr)});
   endmethod
   endinterface
   interface addr = addrServers;

endmodule

interface SglAddrServer#(numeric type addrWidth, numeric type numServers);
   interface Vector#(numServers,Server#(ReqTup,Bit#(addrWidth))) servers;
endinterface

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(addrWidth,numServers));

   FIFOF#(Bit#(TAdd#(1,TLog#(numServers)))) tokFifo <- mkSizedFIFOF(9);
   Vector#(numServers, Server#(ReqTup,Bit#(addrWidth))) addrServers;
   Reg#(Bit#(TLog#(numServers))) arb <- mkReg(0);

   // this is a very crude arbiter.  something more sophisticated may be required (mdk)
   rule inc_arb;
      arb <= arb+1;
   endrule

   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req) if (arb == fromInteger(i));
		tokFifo.enq(fromInteger(i));
		server.request.put(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get() if (tokFifo.first == fromInteger(i));
		tokFifo.deq;
		let rv <- server.response.get;
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface servers = addrServers;

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.

// BSV Libraries
import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import MemTypes::*;
import StmtFSM::*;
import ClientServer::*;
import PortalMemory::*;

typedef 32 MaxNumSGLists;
typedef Bit#(TLog#(MaxNumSGLists)) SGListId;
typedef 12 SGListPageShift0;
typedef 16 SGListPageShift4;
typedef 20 SGListPageShift8;
typedef Bit#(TLog#(MaxNumSGLists)) RegionsIdx;

typedef 8 IndexWidth;

typedef struct {
   SGListId               id;
   Bit#(ObjectOffsetSize) off;
} ReqTup deriving (Eq,Bits,FShow);

`ifdef BSIM
`ifndef PCIE
import "BDPI" function ActionValue#(Bit#(32)) pareff(Bit#(32) handle, Bit#(32) size);
`endif
`endif

interface SGListMMU#(numeric type addrWidth);
   interface SGListSetup setup;
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef struct {
   Bit#(2) pageSize;
   Bit#(SGListPageShift8) value;
} Offset deriving (Eq,Bits,FShow);

typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift0)) Page;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) Page4;
typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) Page8;

typedef struct {
   Bit#(28) barrier;
   Bit#(IndexWidth) idxOffset;
   } Region deriving (Eq,Bits,FShow);

typedef struct {DmaErrorType errorType;
		Bit#(32) pref; } DmaError deriving (Bits);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

   // stage 0 (latency == 1)
   Vector#(2, FIFO#(ReqTup)) incomingReqs <- replicateM(mkFIFO);

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(ReqTup))           reqs0 <- replicateM(mkSizedFIFOF(3));

   // stage 2 (latency == 1)
   Vector#(2,FIFOF#(Tuple3#(Bool,Bool,Bool))) conds <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Tuple3#(Bit#(IndexWidth),Bit#(IndexWidth),Bit#(IndexWidth)))) idxOffsets0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(ReqTup))           reqs1 <- replicateM(mkSizedFIFOF(3));

   // stage 3 (latency == 1)
   Vector#(2,FIFOF#(Offset))           offs0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(IndexWidth)))    idxOffsets1 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))         ptrs1 <- replicateM(mkFIFOF);

   // stage 4 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page) pages <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(Offset))           offs1 <- replicateM(mkSizedFIFOF(3));

   // stage 4 (latnecy == 1)
   Vector#(2,FIFOF#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFOF);

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      dmaIndication.dmaError(extend(pack(error.errorType)), error.pref, -1, 0);
   endrule

   let page_shift0 = fromInteger(valueOf(SGListPageShift0));
   let page_shift4 = fromInteger(valueOf(SGListPageShift4));
   let page_shift8 = fromInteger(valueOf(SGListPageShift8));

   function BRAMServer#(a,b) portsel(BRAM2Port#(a,b) x, Integer i);
      if(i==0) return x.portA;
      else return x.portB;
   endfunction

   for (Integer i = 0; i < 2; i=i+1)
      rule stage1;
	 ReqTup req <- toGet(incomingReqs[i]).get();
	 //match { .ptr, .off } = req;
	 portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(req.id), datain:?});
	 portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(req.id), datain:?});
	 portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(req.id), datain:?});
	 reqs0[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2;
	 ReqTup req <- toGet(reqs0[i]).get;
	 //match {.ptr,.offreq} = req;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;

         Page off = truncate(req.off >> valueOf(SGListPageShift0));
         Page4 off4 = truncate(req.off >> valueOf(SGListPageShift4));
         Page4 off8 = truncate(req.off >> valueOf(SGListPageShift8));
	 let cond8 = off8 < truncate(region8.barrier);
	 let cond4 = off4 < truncate(region4.barrier);
	 let cond0 = off < region0.barrier;

	 conds[i].enq(tuple3(cond8,cond4,cond0));
	 idxOffsets0[i].enq(tuple3(region8.idxOffset,region4.idxOffset, region0.idxOffset));
	 reqs1[i].enq(req);
      endrule
      rule stage3;
	 ReqTup req <- toGet(reqs1[i]).get;
         //match{.ptr,.off} = req;
	 Offset o = Offset{pageSize: 0, value: truncate(req.off)};
	 Bit#(IndexWidth) pbase = 0;
	 Bit#(IndexWidth) idxOffset = 0;

	 match{.cond8,.cond4,.cond0} <- toGet(conds[i]).get;
	 match{.idxOffset8,.idxOffset4,.idxOffset0} <- toGet(idxOffsets0[i]).get;

	 if (cond8) begin
	    //$display("request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 3;
	    pbase = truncate(req.off>>page_shift8);
	    idxOffset = idxOffset8;
	 end
	 else if (cond4) begin
	    //$display("request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 2;
	    pbase = truncate(req.off>>page_shift4);
	    idxOffset = idxOffset4;
	 end
	 else if (cond0) begin
	    //$display("request: req.id=%h req.off=%h", req.id, req.off);
	    o.pageSize = 1;
	    pbase = truncate(req.off>>page_shift0);
	    idxOffset = idxOffset0;
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets1[i].enq(idxOffset);
	 ptrs1[i].enq(req.id);
      endrule
      rule stage4;
	 let off <- toGet(offs0[i]).get();
	 let pbase <- toGet(pbases[i]).get();
	 let idxOffset <- toGet(idxOffsets1[i]).get();
	 let ptr <- toGet(ptrs1[i]).get();
	 Bit#(IndexWidth) p = pbase + idxOffset;
	 if (off.pageSize == 0) begin
	    //FIXME offset
	    //$display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaErrorFifo.enq(DmaError { errorType: DmaErrorBadAddrTrans, pref: extend(ptr) });
	 end
	 //$display("p ages[%d].read %h", i, rp[i].first());
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:{ptr,p}, datain:?});
	 offs1[i].enq(off);
      endrule
      rule stage5;
	 Page page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 //$display("p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(ObjectOffsetSize) rv = ?;
	 Page4 b4 = truncate(page);
	 Page8 b8 = truncate(page);
	 case (offset.pageSize)
	    1: rv = {page,truncate(offset.value)};
	    2: rv = {b4,truncate(offset.value)};
	    3: rv = {b8,truncate(offset.value)};
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   FIFO#(SGListId) configRespFifo <- mkFIFO;
   rule sendConfigResp;
      let ptr <- toGet(configRespFifo).get();
      dmaIndication.configResp(extend(ptr));
   endrule

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		incomingReqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   // FIXME: split this into three methods?
   interface SGListSetup setup;
   method Action region(Bit#(32) pointer, Bit#(64) barr8, Bit#(32) index8, Bit#(64) barr4, Bit#(32) index4, Bit#(64) barr0, Bit#(32) index0);
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(pointer), datain: Region{barrier: truncate(barr8), idxOffset: truncate(index8)}});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(pointer), datain: Region{barrier: truncate(barr4), idxOffset: truncate(index4)}});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: truncate(pointer), datain: Region{barrier: truncate(barr0), idxOffset: truncate(index0)}});
      //$display("region pointer=%d off8=%h off4=%h off0=%h", pointer, off8, off4, off0);
      configRespFifo.enq(truncate(pointer));
   endmethod

   method Action sglist(Bit#(32) pointer, Bit#(32) pointerIndex, Bit#(64) addr,  Bit#(32) len);
`ifdef BSIM
`ifndef PCIE
	 let va <- pareff(pointer, len);
`endif
`endif
         Bit#(IndexWidth) ind = truncate(pointerIndex);
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(pointer),ind}, datain:truncate(addr)});
   endmethod
   endinterface
   interface addr = addrServers;

endmodule

interface SglAddrServer#(numeric type addrWidth, numeric type numServers);
   interface Vector#(numServers,Server#(ReqTup,Bit#(addrWidth))) servers;
endinterface

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(addrWidth,numServers));

   FIFOF#(Bit#(TAdd#(1,TLog#(numServers)))) tokFifo <- mkSizedFIFOF(9);
   Vector#(numServers, Server#(ReqTup,Bit#(addrWidth))) addrServers;
   Reg#(Bit#(TLog#(numServers))) arb <- mkReg(0);

   // this is a very crude arbiter.  something more sophisticated may be required (mdk)
   rule inc_arb;
      arb <= arb+1;
   endrule

   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req) if (arb == fromInteger(i));
		tokFifo.enq(fromInteger(i));
		server.request.put(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get() if (tokFifo.first == fromInteger(i));
		tokFifo.deq;
		let rv <- server.response.get;
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface servers = addrServers;

endmodule