ingress pipeline takes vec()

ingress pipeline takes vec()

package ParserTest;

import BRAMFIFO::*;
import BuildVector::*;
import Clocks::*;
import Connectable::*;
import DefaultValue::*;
import GetPut::*;
import ClientServer::*;
import StmtFSM::*;
import FIFO::*;
import FIFOF::*;
import Pipe::*;
import Vector::*;
import ConnectalMemory::*;

import Ethernet::*;
import PacketBuffer::*;
import MemTypes::*;
import MemServerIndication::*;
import MMUIndication::*;
import Paxos::*;
import SharedBuff::*;
import HostChannel::*;
import TxChannel::*;
import PaxosIngressPipeline::*;
import Sims::*;
import PaxosTypes::*;
//import RoundRegister::*;
//import RoleRegister::*;

typedef 12 PktSize; // maximum 4096b
typedef TDiv#(`DataBusWidth, 32) WordsPerBeat;

interface ParserTestIndication;
   method Action read_version_resp(Bit#(32) version);
//   method Action parsed_ipv4_resp(Bit#(8) ttl);
//   method Action parsed_vlan_resp();
//   method Action parsed_ether_resp(Bit#(48) srcAddr, Bit#(48) dstAddr);
endinterface

interface ParserTestRequest;
   method Action read_version();
   method Action writePacketData(Vector#(2, Bit#(64)) data, Vector#(2, Bit#(8)) mask, Bit#(1) sop, Bit#(1) eop);
endinterface

interface ParserTest;
   interface ParserTestRequest request;
endinterface
module mkParserTest#(ParserTestIndication indication
                    ,ConnectalMemory::MemServerIndication memServerInd
                    )(ParserTest);
   let verbose = True;
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   SimClocks clocks <- mkSimClocks();
   Clock txClock = clocks.clock_156_25;
   Reset txReset <- mkSyncReset(2, defaultReset, txClock);

   HostChannel hostchan <- mkHostChannel();
   PaxosIngressPipeline ingress <- mkPaxosIngressPipeline(vec(hostchan.next));
   TxChannel txchan <- mkTxChannel(txClock, txReset);
   SyncFIFOIfc#(EtherData) txSyncFifo <- mkSyncBRAMFIFO(6, txClock, txReset, defaultClock, defaultReset);

   SharedBuffer#(12, 128, 1) mem <- mkSharedBuffer(vec(txchan.readClient)
                                                  ,vec(txchan.freeClient)
                                                  ,vec(hostchan.writeClient, ingress.writeClient)
                                                  ,vec(hostchan.mallocClient)
                                                  ,memServerInd
                                                  );

   mkConnection(ingress.eventPktSend, txchan.eventPktSend);
   //P4Register#(InstanceSize, RoundSize) roundRegs <- mkP4RoundRegister(vec(roleTable.regAccess));
   //P4Register#(1, 8) roleRegs <- mkP4RoleRegister(vec(roundTable.regAccess));

   interface ParserTestRequest request;
      method Action read_version();
         let v= `NicVersion;
         $display("read version");
         indication.read_version_resp(v);
      endmethod
      method Action writePacketData(Vector#(2, Bit#(64)) data, Vector#(2, Bit#(8)) mask, Bit#(1) sop, Bit#(1) eop);
         EtherData beat = defaultValue;
         beat.data = pack(reverse(data));
         beat.mask = pack(reverse(mask));
         beat.sop = unpack(sop);
         beat.eop = unpack(eop);
         hostchan.writeServer.writeData.put(beat);
      endmethod
   endinterface
endmodule: mkParserTest
endpackage: ParserTest

package ParserTest;

import BRAMFIFO::*;
import BuildVector::*;
import Clocks::*;
import Connectable::*;
import DefaultValue::*;
import GetPut::*;
import ClientServer::*;
import StmtFSM::*;
import FIFO::*;
import FIFOF::*;
import Pipe::*;
import Vector::*;
import ConnectalMemory::*;

import Ethernet::*;
import PacketBuffer::*;
import MemTypes::*;
import MemServerIndication::*;
import MMUIndication::*;
import Paxos::*;
import SharedBuff::*;
import HostChannel::*;
import TxChannel::*;
import PaxosIngressPipeline::*;
import Sims::*;
import PaxosTypes::*;
//import RoundRegister::*;
//import RoleRegister::*;

typedef 12 PktSize; // maximum 4096b
typedef TDiv#(`DataBusWidth, 32) WordsPerBeat;

interface ParserTestIndication;
   method Action read_version_resp(Bit#(32) version);
//   method Action parsed_ipv4_resp(Bit#(8) ttl);
//   method Action parsed_vlan_resp();
//   method Action parsed_ether_resp(Bit#(48) srcAddr, Bit#(48) dstAddr);
endinterface

interface ParserTestRequest;
   method Action read_version();
   method Action writePacketData(Vector#(2, Bit#(64)) data, Vector#(2, Bit#(8)) mask, Bit#(1) sop, Bit#(1) eop);
endinterface

interface ParserTest;
   interface ParserTestRequest request;
endinterface
module mkParserTest#(ParserTestIndication indication
                    ,ConnectalMemory::MemServerIndication memServerInd
                    )(ParserTest);
   let verbose = True;
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   SimClocks clocks <- mkSimClocks();
   Clock txClock = clocks.clock_156_25;
   Reset txReset <- mkSyncReset(2, defaultReset, txClock);

   HostChannel hostchan <- mkHostChannel();
   PaxosIngressPipeline ingress <- mkPaxosIngressPipeline(hostchan.next);
   TxChannel txchan <- mkTxChannel(txClock, txReset);
   SyncFIFOIfc#(EtherData) txSyncFifo <- mkSyncBRAMFIFO(6, txClock, txReset, defaultClock, defaultReset);

   SharedBuffer#(12, 128, 1) mem <- mkSharedBuffer(vec(txchan.readClient)
                                                  ,vec(txchan.freeClient)
                                                  ,vec(hostchan.writeClient, ingress.writeClient)
                                                  ,vec(hostchan.mallocClient)
                                                  ,memServerInd
                                                  );

   mkConnection(ingress.eventPktSend, txchan.eventPktSend);
   //P4Register#(InstanceSize, RoundSize) roundRegs <- mkP4RoundRegister(vec(roleTable.regAccess));
   //P4Register#(1, 8) roleRegs <- mkP4RoleRegister(vec(roundTable.regAccess));

   interface ParserTestRequest request;
      method Action read_version();
         let v= `NicVersion;
         $display("read version");
         indication.read_version_resp(v);
      endmethod
      method Action writePacketData(Vector#(2, Bit#(64)) data, Vector#(2, Bit#(8)) mask, Bit#(1) sop, Bit#(1) eop);
         EtherData beat = defaultValue;
         beat.data = pack(reverse(data));
         beat.mask = pack(reverse(mask));
         beat.sop = unpack(sop);
         beat.eop = unpack(eop);
         hostchan.writeServer.writeData.put(beat);
      endmethod
   endinterface
endmodule: mkParserTest
endpackage: ParserTest


Changed size to numeric type instead of integer in SFIFO

package SFIFO;

import Ehr::*;
import Vector::*;

interface SFIFO#(numeric type size, type dataType, type searchType);
    method Action enq(dataType x);
    method Action deq;
    method dataType first;
    method Action clear;
    method Bool search(searchType x);
endinterface

// search < {enq , deq} < clear
// first < deq
module mkSFIFO#(function Bool isMatch(searchType s, dataType d))(SFIFO#(size, dataType, searchType)) provisos (Bits#(dataType, dataSize));
    // use valid bits to make search logic smaller
    Vector#(size, Reg#(Maybe#(dataType))) data <- replicateM(mkRegU);
    Reg#(Bit#(TLog#(size))) enqP <- mkReg(0);
    Reg#(Bit#(TLog#(size))) deqP <- mkReg(0);
    Reg#(Bool) full <- mkReg(False);
    Reg#(Bool) empty <- mkReg(True);
    // EHRs to avoid conflicts between enq and deq
    Ehr#(3, Bool) deqReq <- mkEhr(False);
    Ehr#(3, Maybe#(dataType)) enqReq <- mkEhr(tagged Invalid);

    // Canonicalize rule to handle enq and deq.
    // These attributes are statically checked by the compiler.
    (* fire_when_enabled *)         // WILL_FIRE == CAN_FIRE
    (* no_implicit_conditions *)    // CAN_FIRE == guard (True)
    rule canonicalize;
        Bool enqueued = False;
        let nextEnqP = enqP;
        Bool dequeued = False;
        let nextDeqP = deqP;

        // enqueue logic
        if (enqReq[2] matches tagged Valid .enqVal) begin
            enqueued = True;
            nextEnqP = (enqP == fromInteger(valueOf(size) - 1)) ? 0 : enqP + 1;
            // perform state updates
            data[enqP] <= tagged Valid enqVal;
            enqP <= nextEnqP;
        end

        // dequeue logic
        if (deqReq[2] == True) begin
            dequeued = True;
            nextDeqP = (deqP == fromInteger(valueOf(size) - 1)) ? 0 : deqP + 1;
            // perform state updates
            deqP <= nextDeqP;
            data[deqP] <= tagged Invalid;
        end

        // update empty and full if an element was enqueued or dequeued
        if (enqueued || dequeued) begin
            full <= (nextEnqP == nextDeqP) ? enqueued : False;
            empty <= (nextEnqP == nextDeqP) ? dequeued : False;
            enqP <= nextEnqP;
            deqP <= nextDeqP;
        end

        // clear request EHRs
        enqReq[2] <= tagged Invalid;
        deqReq[2] <= False;
    endrule

    method Action enq(dataType x) if (!full && !isValid(enqReq[0]));
        enqReq[0] <= tagged Valid x;
    endmethod
    method Action deq if (!empty && !deqReq[0]);
        deqReq[0] <= True;
    endmethod
    method dataType first if (!empty && !deqReq[0]);
        return fromMaybe(?, data[deqP]);
    endmethod
    method Action clear;
        writeVReg(data, replicate(tagged Invalid));
        enqP <= 0;
        deqP <= 0;
        full <= False;
        empty <= True;
        // clear any pending enq or deq
        enqReq[1] <= tagged Invalid;
        deqReq[1] <= False;
    endmethod

    // different search implementations
    // search < {enq, deq}
    method Bool search(searchType x) if (!isValid(enqReq[0]) && !deqReq[0]);
        // helper function for isMatch when dataType has valid bits
        function Bool maybeIsMatch(searchType s, Maybe#(dataType) md);
            return md matches tagged Valid. d ? isMatch(s, d) : False;
        endfunction
        return any(id, map(compose(maybeIsMatch(x), readReg), data));
    endmethod

    // // Alternate search implementation with the scheulde:
    // //   deq < search < enq
    // method Bool search(searchType x) if (!isValid(enqReq[0]));
    //     // compute dataPostDeq by considering deqReq[1]
    //     Vector#(size, Maybe#(dataType)) dataPostDeq = readVReg(data);
    //     if (deqReq[1]) begin
    //         dataPostDeq[deqP] = tagged Invalid;
    //     end
    //     // helper function for isMatch when dataType has valid bits
    //     function Bool maybeIsMatch(searchType s, Maybe#(dataType) md);
    //         return md matches tagged Valid. d ? isMatch(s, d) : False;
    //     endfunction
    //     return any(map(maybeIsMatch(x), dataPostDeq));
    // endmethod
endmodule

endpackage

package SFIFO;

import Ehr::*;
import List::*;

// If you are running into a problem because MAX_SFIFO_SIZE is too small, you
// can increase it here, or you can define it
`ifndef MAX_SFIFO_SIZE
`define MAX_SFIFO_SIZE 16
`endif

interface SFIFO#(type dataType, type searchType);
    method Action enq(dataType x);
    method Action deq;
    method dataType first;
    method Action clear;
    method Bool search(searchType x);
endinterface

// search < {enq , deq} < clear
// first < deq
module mkSFIFO#(Integer size, function Bool isMatch(searchType s, dataType d))(SFIFO#(dataType, searchType)) provisos (Bits#(dataType, dataSize));
    // use valid bits to make search logic smaller
    List#(Reg#(Maybe#(dataType))) data <- List::replicateM(size, mkRegU);
    Reg#(Bit#(TLog#(`MAX_SFIFO_SIZE))) enqP <- mkReg(0);
    Reg#(Bit#(TLog#(`MAX_SFIFO_SIZE))) deqP <- mkReg(0);
    Reg#(Bool) full <- mkReg(False);
    Reg#(Bool) empty <- mkReg(True);
    // EHRs to avoid conflicts between enq and deq
    Ehr#(3, Bool) deqReq <- mkEhr(False);
    Ehr#(3, Maybe#(dataType)) enqReq <- mkEhr(tagged Invalid);

    // Canonicalize rule to handle enq and deq.
    // These attributes are statically checked by the compiler.
    (* fire_when_enabled *)         // WILL_FIRE == CAN_FIRE
    (* no_implicit_conditions *)    // CAN_FIRE == guard (True)
    rule canonicalize;
        Bool enqueued = False;
        let nextEnqP = enqP;
        Bool dequeued = False;
        let nextDeqP = deqP;

        // enqueue logic
        if (enqReq[2] matches tagged Valid .enqVal) begin
            enqueued = True;
            nextEnqP = (enqP == fromInteger(size - 1)) ? 0 : enqP + 1;
            // perform state updates
            data[enqP] <= tagged Valid enqVal;
            enqP <= nextEnqP;
        end

        // dequeue logic
        if (deqReq[2] == True) begin
            dequeued = True;
            nextDeqP = (deqP == fromInteger(size - 1)) ? 0 : deqP + 1;
            // perform state updates
            deqP <= nextDeqP;
            data[deqP] <= tagged Invalid;
        end

        // update empty and full if an element was enqueued or dequeued
        if (enqueued || dequeued) begin
            full <= (nextEnqP == nextDeqP) ? enqueued : False;
            empty <= (nextEnqP == nextDeqP) ? dequeued : False;
            enqP <= nextEnqP;
            deqP <= nextDeqP;
        end

        // clear request EHRs
        enqReq[2] <= tagged Invalid;
        deqReq[2] <= False;
    endrule

    method Action enq(dataType x) if (!full && !isValid(enqReq[0]));
        enqReq[0] <= tagged Valid x;
    endmethod
    method Action deq if (!empty && !deqReq[0]);
        deqReq[0] <= True;
    endmethod
    method dataType first if (!empty && !deqReq[0]);
        return fromMaybe(?, data[deqP]);
    endmethod
    method Action clear;
        for (Integer i = 0 ; i < size ; i = i+1) begin
            data[i] <= tagged Invalid;
        end
        enqP <= 0;
        deqP <= 0;
        full <= False;
        empty <= True;
        // clear any pending enq or deq
        enqReq[1] <= tagged Invalid;
        deqReq[1] <= False;
    endmethod

    // different search implementations
    // search < {enq, deq}
    method Bool search(searchType x) if (!isValid(enqReq[0]) && !deqReq[0]);
        // helper function for isMatch when dataType has valid bits
        function Bool maybeIsMatch(searchType s, Maybe#(dataType) md);
            return md matches tagged Valid. d ? isMatch(s, d) : False;
        endfunction
        return any(id, map(compose(maybeIsMatch(x), readReg), data));
    endmethod

    // // Alternate search implementation with the scheulde:
    // //   deq < search < enq
    // method Bool search(searchType x) if (!isValid(enqReq[0]));
    //     // compute dataPostDeq by considering deqReq[1]
    //     List#(Maybe#(dataType)) dataPostDeq = map(readReg, data);
    //     if (deqReq[1]) begin
    //         dataPostDeq[deqP] = tagged Invalid;
    //     end
    //     // helper function for isMatch when dataType has valid bits
    //     function Bool maybeIsMatch(searchType s, Maybe#(dataType) md);
    //         return md matches tagged Valid. d ? isMatch(s, d) : False;
    //     endfunction
    //     return any(map(maybeIsMatch(x), dataPostDeq));
    // endmethod
endmodule

endpackage


fixed termination detection of request and setting of d.last

// 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#(dataWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(dataWidth, 8), 8, dataWidth)
	    ,Add#(1, a__, numServers)
	    ,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(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemreadEngineBuff#(Integer bufferSizeBytes) (MemreadEngine#(dataWidth, cmdQDepth, numServers))
   provisos (Div#(dataWidth,8,dataWidthBytes),
	     Mul#(dataWidthBytes,8,dataWidth),
	     Log#(dataWidthBytes,beatShift),
	     Log#(cmdQDepth,logCmdQDepth),
	     Mul#(cmdQDepth,numServers,cmdBuffSz),
	     Log#(cmdBuffSz, cmdBuffAddrSz),
	     Log#(numServers, serverIdxSz),
	     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(dataWidthBytes);
   Vector#(numServers, Reg#(Bool))               outs1 <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))     buffCap <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))     cmdRegs <- replicateM(mkReg(unpack(0)));

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))              loadf_b <- mkSizedFIFO(1);
   FIFO#(Tuple3#(Bit#(serverIdxSz),MemengineCmd,Bool)) loadf_c <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool))        workf <- mkSizedBRAMFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(void))              outfs <- replicateM(mkSizedFIFO(valueOf(cmdQDepth)));
   Vector#(numServers, FIFO#(MemengineCmd))    cmds_in <- replicateM(mkFIFO());

   FIFOF#(MemData#(dataWidth))                             read_data <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemData#(dataWidth)))  read_data_buffs <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(Bit#(dataWidth)) check_out(PipeOut#(MemData#(dataWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method Bit#(dataWidth) first;
	     return inpipe.first.data;
	  endmethod
	  method Action deq;
	     if (verbose) $display("check_out: idx %d data %h buffCap %d eob %d", i, inpipe.first.data, buffCap[i].read(), inpipe.first.last);
	     inpipe.deq;
	     buffCap[i].increment(1);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(Bit#(dataWidth))) read_data_pipes = zipWith(check_out, map(toPipeOut,read_data_buffs), 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));

   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 (!outs1[idx]);
	 let cmd <- toGet(cmds_in[idx]).get();
	 outs1[idx] <= True;
	 cmdRegs[idx] <= cmd;
	 if (verbose) $display("mkMemreadEngineBuff::store_cmd %d %d", idx, buffCap[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (outs1[loadIdx]) begin
	 load_in_progress <= True;
	 let cmd = cmdRegs[loadIdx];
	 let cond0 <- buffCap[loadIdx].maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let last_burst = cmd.len <= extend(cmd.burstLen);
	 loadf_b.enq(tuple3(cmd,cond0,last_burst));
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_b buffCap %d burstLen %d cond0 %d last_burst %d", buffCap[loadIdx].read(), cmd.burstLen>>beat_shift, cond0, last_burst);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for outs1 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,.last_burst} <- toGet(loadf_b).get;
      if  (cond0) begin
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_c cmd.len %d idx %d cond0 %d last_burst %d", cmd.len, loadIdx, cond0, last_burst);
	 let x = cmd.burstLen;
	 if (cmd.len < extend(cmd.burstLen))
	    x = truncate(cmd.len);
	 loadf_c.enq(tuple3(truncate(loadIdx),cmd,last_burst));
	 if (last_burst) begin
	    if (verbose) $display("load_ctxt_b last_burst %d", last_burst);
	    outfs[loadIdx].enq(?);
	    outs1[loadIdx] <= False;
	 end
	 else begin
	    let new_cmd = MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
				       burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	    cmdRegs[loadIdx] <= new_cmd;
	 end
      end
   endrule

   rule read_data_rule;
      let d <- toGet(read_data).get();
      match {.rc, .idx, .last_burst} = workf.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("%h new_respCnt %d rc %d last_burst %d idx %d outs1 %d eob %d", d.data, new_respCnt, rc, last_burst, idx, outs1[idx], d.last);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 workf.deq;
	 //$display("eob %d", idx);
	 l = last_burst;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      d.last = l;
      read_data_buffs[idx].enq(d);
   endrule

   function MemreadServer#(dataWidth) toMemreadServer(Server#(MemengineCmd,Bool) cs, PipeOut#(Bit#(dataWidth)) p) =
      (interface MemreadServer;
	  interface cmdServer = cs;
	  interface dataPipe  = p;
       endinterface);

   Vector#(numServers, Server#(MemengineCmd,Bool)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface Server#(MemengineCmd,Bool);
		  interface Put request;
		     method Action put(MemengineCmd cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef BSIM
			Bit#(32) dw = fromInteger(valueOf(dataWidthBytes));
			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 begin
`endif
			   cmds_in[i].enq(cmd);
`ifdef BSIM
			end
`endif
 		     endmethod
		  endinterface
		  interface Get response;
		     method ActionValue#(Bool) get;
			outfs[i].deq;
			return True;
		     endmethod
		  endinterface
	       endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd, .last_burst} <- toGet(loadf_c).get;
	    Bit#(BurstLenSize) bl = cmd.burstLen;
	    if (last_burst) begin
	       bl = truncate(cmd.len);
	    end
	    workf.enq(tuple3(truncate(bl>>beat_shift), idx, last_burst));
	    if (verbose) $display("MemreadEngine::readReq idx %d offset %h burstLenBytes %h last_burst %d", idx, cmd.base, bl, last_burst);
	    return MemRequest { sglId: cmd.sglId, offset: cmd.base, burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)};
	 endmethod
      endinterface
      interface Put readData = toPut(read_data);
   endinterface
   interface dataPipes = read_data_pipes;
   interface read_servers = zipWith(toMemreadServer, rs, read_data_pipes);
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#(dataWidth, cmdQDepth, numServers))
   provisos( Mul#(TDiv#(dataWidth, 8), 8, dataWidth)
	    ,Add#(1, a__, numServers)
	    ,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(TExp#(BurstLenSize)));
   return rv;
endmodule

module mkMemreadEngineBuff#(Integer bufferSizeBytes) (MemreadEngine#(dataWidth, cmdQDepth, numServers))
   provisos (Div#(dataWidth,8,dataWidthBytes),
	     Mul#(dataWidthBytes,8,dataWidth),
	     Log#(dataWidthBytes,beatShift),
	     Log#(cmdQDepth,logCmdQDepth),
	     Mul#(cmdQDepth,numServers,cmdBuffSz),
	     Log#(cmdBuffSz, cmdBuffAddrSz),
	     Log#(numServers, serverIdxSz),
	     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(dataWidthBytes);
   Vector#(numServers, Reg#(Bool))               outs1 <- replicateM(mkReg(False));
   Vector#(numServers, ConfigCounter#(16))     buffCap <- replicateM(mkConfigCounter(fromInteger(bufferSizeBeats)));
   Vector#(numServers, Reg#(MemengineCmd))     cmdRegs <- replicateM(mkReg(unpack(0)));

   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))         loadf_b <- mkSizedFIFO(1);
   FIFO#(Tuple2#(Bit#(serverIdxSz),MemengineCmd)) loadf_c <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(serverIdxSz),Bool))   workf <- mkSizedBRAMFIFO(valueOf(cmdQDepth));

   Vector#(numServers, FIFO#(void))              outfs <- replicateM(mkSizedFIFO(1));
   Vector#(numServers, FIFO#(MemengineCmd))    cmds_in <- replicateM(mkFIFO());

   FIFOF#(MemData#(dataWidth))                             read_data <- mkFIFOF;
   Vector#(numServers, FIFOF#(MemData#(dataWidth)))  read_data_buffs <- replicateM(mkSizedBRAMFIFOF(bufferSizeBeats));
   function PipeOut#(Bit#(dataWidth)) check_out(PipeOut#(MemData#(dataWidth)) inpipe, Integer i) =
      (interface PipeOut;
	  method Bit#(dataWidth) first;
	     return inpipe.first.data;
	  endmethod
	  method Action deq;
	     if (verbose) $display("check_out: idx %d data %h", i, inpipe.first.data);
	     inpipe.deq;
	     buffCap[i].increment(1);
	     if (inpipe.first.last)
		outfs[i].enq(?);
	  endmethod
	  method Bool notEmpty = inpipe.notEmpty;
       endinterface);
   Vector#(numServers, PipeOut#(Bit#(dataWidth))) read_data_pipes = zipWith(check_out, map(toPipeOut,read_data_buffs), 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));

   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 (!outs1[idx]);
	 let cmd <- toGet(cmds_in[idx]).get();
	 outs1[idx] <= True;
	 cmdRegs[idx] <= cmd;
	 if (verbose) $display("mkMemreadEngineBuff::store_cmd %d %d", idx, buffCap[idx].read);
      endrule

   rule load_ctxt_a (!load_in_progress);
      if (outs1[loadIdx]) begin
	 load_in_progress <= True;
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_a %d", loadIdx);
	 let cmd = cmdRegs[loadIdx];
	 let cond0 <- buffCap[loadIdx].maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 loadf_b.enq(tuple3(cmd,cond0,cond1));
	 if (verbose) $display("mkMemreadEngineBuff::load_ctxt_b %d %d", buffCap[loadIdx].read(), cmd.burstLen>>beat_shift);
      end
      else begin
	 incr_loadIdx;
      end
   endrule

   // should use an EHR for outs1 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,.cond1} <- toGet(loadf_b).get;
      if (verbose) $display("mkMemreadEngineBuff::load_ctxt_c cmd.len %d idx %d cond0 %d cond1 %d", cmd.len, loadIdx, cond0, cond1);
      if  (cond0) begin
	 let x = cmd.burstLen;
	 if (cmd.len < extend(cmd.burstLen))
	    x = truncate(cmd.len);
	 loadf_c.enq(tuple2(truncate(loadIdx),cmd));
	 if (cond1) begin
	    if (verbose) $display("load_ctxt_b cond1 %d", cond1);
	    outs1[loadIdx] <= False;
	 end
	 else begin
	    let new_cmd = MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
				       burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	    cmdRegs[loadIdx] <= new_cmd;
	 end
      end
   endrule

   rule read_data_rule;
      let d <- toGet(read_data).get();
      match {.rc, .idx, .last} = workf.first;
      let new_respCnt = respCnt+1;
      let l = False;
      if (verbose) $display("%h new_respCnt %d rc %d last_burst %d idx %d outs1 %d", d.data, new_respCnt, rc, last, idx, outs1[idx]);
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 workf.deq;
	 //$display("eob %d", idx);
	 l = last;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      read_data_buffs[idx].enq(d);
   endrule

   function MemreadServer#(dataWidth) toMemreadServer(Server#(MemengineCmd,Bool) cs, PipeOut#(Bit#(dataWidth)) p) =
      (interface MemreadServer;
	  interface cmdServer = cs;
	  interface dataPipe  = p;
       endinterface);

   Vector#(numServers, Server#(MemengineCmd,Bool)) rs;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      rs[i] = (interface Server#(MemengineCmd,Bool);
		  interface Put request;
		     method Action put(MemengineCmd cmd);
			Bit#(32) bsb = fromInteger(bufferSizeBytes);
`ifdef BSIM
			Bit#(32) dw = fromInteger(valueOf(dataWidthBytes));
			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 begin
`endif
			   cmds_in[i].enq(cmd);
`ifdef BSIM
			end
`endif
 		     endmethod
		  endinterface
		  interface Get response;
		     method ActionValue#(Bool) get;
			outfs[i].deq;
			return True;
		     endmethod
		  endinterface
	       endinterface);
   interface readServers = rs;
   interface MemReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(MemRequest) get();
	    match {.idx, .cmd} <- toGet(loadf_c).get;
	    Bit#(BurstLenSize) bl = cmd.burstLen;
	    let last = False;
	    if (cmd.len <= extend(bl)) begin
	       last = True;
	       bl = truncate(cmd.len);
	    end
	    workf.enq(tuple3(truncate(bl>>beat_shift), idx, last));
	    if (verbose) $display("MemreadEngine::readReq %d, %h %h %h", idx, cmd.base, bl, last);
	    return MemRequest { sglId: cmd.sglId, offset: cmd.base, burstLen:bl, tag: (cmd.tag << valueOf(serverIdxSz)) | extend(idx)};
	 endmethod
      endinterface
      interface Put readData = toPut(read_data);
   endinterface
   interface dataPipes = read_data_pipes;
   interface read_servers = zipWith(toMemreadServer, rs, read_data_pipes);
endmodule


Set UDP checksum to 0 in deparser

Set UDP checksum to 0 in deparser

// Copyright (c) 2016 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.
import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import DbgDefs::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;
import Pipe::*;
import Ethernet::*;
import PaxosTypes::*;
import PacketBuffer::*;
import P4Types::*;
import Utils::*;

typedef enum {
   StateDeparseIdle,
   StateDeparseEthernet,
   StateDeparseArp,
   StateDeparseIpv4,
   StateDeparseIpv6,
   StateDeparseUdp,
   StateDeparsePaxos
} DeparserState deriving (Bits, Eq, FShow);

function Tuple2#(EthernetT, EthernetT) toEthernet(MetadataT meta);
   EthernetT data = defaultValue;
   EthernetT mask = defaultMask;
   data.dstAddr = fromMaybe(?, meta.dstAddr);
   mask.dstAddr = 0;
   data.etherType = fromMaybe(?, meta.etherType);
   mask.etherType = 0;
   return tuple2(data, mask);
endfunction

function Tuple2#(Ipv4T, Ipv4T) toIpv4(MetadataT meta);
   Ipv4T ipv4 = defaultValue;
   Ipv4T mask = defaultMask;
   ipv4.protocol = fromMaybe(?, meta.protocol);
   mask.protocol = 0;
   return tuple2(ipv4, mask);
endfunction

function Tuple2#(UdpT, UdpT) toUdp(MetadataT meta);
   UdpT udp = defaultValue;
   UdpT mask = defaultMask;
   udp.dstPort = fromMaybe(?, meta.dstPort);
   mask.dstPort = 0;
   udp.checksum = 0;
   mask.checksum = 0;
   return tuple2(udp, mask);
endfunction

function Tuple2#(Ipv6T, Ipv6T) toIpv6(MetadataT meta);
   Ipv6T ipv6 = defaultValue;
   Ipv6T mask = defaultMask;
   return tuple2(ipv6, mask);
endfunction

//
function Tuple2#(PaxosT, PaxosT) toPaxos(MetadataT meta);
   PaxosT paxos = defaultValue;
   PaxosT mask = defaultMask;
   paxos.inst = fromMaybe(?, meta.paxos$inst);
   mask.inst = 0;
   paxos.rnd = fromMaybe(?, meta.paxos$rnd);
   mask.rnd = 0;
   paxos.vrnd = fromMaybe(?, meta.paxos$vrnd);
   mask.vrnd = 0;
   paxos.acptid = fromMaybe(?, meta.paxos$acptid);
   mask.acptid = 0;
   paxos.paxosval = fromMaybe(?, meta.paxos$paxosval);
   mask.paxosval = 0;
   return tuple2(paxos, mask);
endfunction

module mkStateDeparseIdle#(Reg#(DeparserState) state, FIFOF#(EtherData) datain, FIFOF#(EtherData) dataout, Wire#(Bool) start_fsm)(Empty);

   rule load_packet if (state == StateDeparseIdle);
      let v = datain.first;
      if (v.sop) begin
         state <= StateDeparseEthernet;
         start_fsm <= True;
         $display("(%0d) Deparse Ethernet Start", $time);
      end
      else begin
         datain.deq;
         dataout.enq(v);
         $display("(%0d) payload ", $time, fshow(v));
         start_fsm <= False;
      end
   endrule
endmodule

interface DeparseEthernet;
   interface Get#(EtherData) deparse_arp;
   interface Get#(EtherData) deparse_ipv4;
   interface Get#(EtherData) deparse_ipv6;
   method Action start;
   method Action clear;
endinterface

module mkStateDeparseEthernet#(Reg#(DeparserState) state,
                               FIFOF#(EtherData) datain,
                               FIFOF#(EtherData) dataout,
                               FIFOF#(EthernetT) ethernet_meta,
                               FIFOF#(EthernetT) ethernet_mask)
                               (DeparseEthernet);
   let verbose = False;
   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFO#(EtherData) parse_arp_fifo <- mkFIFO;
   FIFO#(EtherData) parse_ipv4_fifo <- mkFIFO;
   FIFO#(EtherData) parse_ipv6_fifo <- mkFIFO;

   PulseWire start_wire <- mkPulseWire;
   PulseWire clear_wire <- mkPulseWire;

   function DeparserState compute_next_state(Bit#(16) etherType);
       DeparserState nextState = StateDeparseIdle;
       case (byteSwap(etherType)) matches
           'h806: begin
               nextState=StateDeparseArp;
           end
           'h800: begin
               nextState=StateDeparseIpv4;
           end
           'h86dd: begin
               nextState=StateDeparseIpv6;
           end
           default: begin
               nextState=StateDeparseIdle;
           end
       endcase
       return nextState;
   endfunction

   rule load_packet if (state == StateDeparseEthernet);
      let data_current <- toGet(datain).get;
      packet_in_wire <= data_current;
      $display("(%0d) Ether: ", $time, fshow(data_current));
   endrule

   Stmt deparse_ethernet =
   seq
   action
      let data_this_cycle = packet_in_wire;
      let metadata = ethernet_meta.first;
      let mask = ethernet_mask.first;
      Vector#(128, Bit#(1)) dataVec = unpack(data_this_cycle.data);
      Vector#(112, Bit#(1)) hdr = takeAt(0, dataVec);
      Vector#(16, Bit#(1)) unchanged = takeAt(112, dataVec);
      EthernetT ethernet = unpack(pack(hdr));
      let nextState = compute_next_state(metadata.etherType);
      if (verbose) $display("(%0d) Eth: %h", $time, metadata.etherType);
      if (verbose) $display("(%0d) Goto ", $time, fshow(nextState));
      data_this_cycle.data = {pack(unchanged), pack(hdr)};
      if (nextState == StateDeparseArp) begin
         parse_arp_fifo.enq(data_this_cycle);
      end
      else if (nextState == StateDeparseIpv4) begin
         parse_ipv4_fifo.enq(data_this_cycle);
      end
      else if (nextState == StateDeparseIpv6) begin
         parse_ipv6_fifo.enq(data_this_cycle);
      end
      state <= nextState;
      ethernet_meta.deq;
      ethernet_mask.deq;
   endaction
   endseq;

   FSM fsm_deparse_ethernet <- mkFSM(deparse_ethernet);
   rule start_fsm if (start_wire);
      fsm_deparse_ethernet.start;
   endrule
   rule clear_fsm if (clear_wire);
      fsm_deparse_ethernet.abort;
   endrule
   method Action start();
      start_wire.send();
   endmethod
   method Action clear();
      clear_wire.send();
   endmethod
   interface deparse_arp = toGet(parse_arp_fifo);
   interface deparse_ipv4 = toGet(parse_ipv4_fifo);
   interface deparse_ipv6 = toGet(parse_ipv6_fifo);
endmodule

interface DeparseIpv4;
   interface Put#(EtherData) deparse_ethernet;
   interface Get#(EtherData) deparse_udp;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparseIpv4#(Reg#(DeparserState) state,
                           FIFOF#(EtherData) datain,
                           FIFOF#(EtherData) dataout,
                           FIFOF#(Ipv4T) ipv4_meta,
                           FIFOF#(Ipv4T) ipv4_mask)
                           (DeparseIpv4);

   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_ethernet_fifo <- mkBypassFIFOF;
   FIFO#(EtherData) deparse_udp_fifo <- mkFIFO;
   PulseWire start_wire <- mkPulseWire();
   PulseWire clear_wire <- mkPulseWire();

   function DeparserState compute_next_state(Bit#(8) protocol);
       DeparserState nextState = StateDeparseIdle;
       case (byteSwap(protocol)) matches
           'h11: begin
               nextState=StateDeparseUdp;
           end
           default: begin
               nextState=StateDeparseIdle;
           end
       endcase
       return nextState;
   endfunction

   rule load_packet if (state == StateDeparseIpv4 && !deparse_ethernet_fifo.notEmpty());
       let data_current <- toGet(datain).get;
       packet_in_wire <= data_current;
       $display("(%0d) IPv4: ", $time, fshow(data_current));
   endrule

   Stmt deparse_ipv4 =
   seq
   action
      let data_this_cycle <- toGet(deparse_ethernet_fifo).get;
      Vector#(112, Bit#(1)) last_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) data = takeAt(112, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(ipv4_meta.first))));
      Vector#(16, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(ipv4_mask.first))));
      let masked_data = pack(data) & pack(curr_mask);
      let out_data = masked_data | pack(curr_meta);
      $display("(%0d) IPv4: [1] ", $time, fshow(data_this_cycle), " meta=%h, mask=%h", curr_mask, curr_meta);
      data_this_cycle.data = {out_data, pack(last_data)};
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      Vector#(128, Bit#(1)) curr_meta = takeAt(16, unpack(byteSwap(pack(ipv4_meta.first))));
      Vector#(128, Bit#(1)) curr_mask = takeAt(16, unpack(byteSwap(pack(ipv4_mask.first))));
      let masked_data = data_this_cycle.data & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      data_this_cycle.data = curr_data;
      dataout.enq(data_this_cycle);
      $display("(%0d) IPv4: [2] ", $time, fshow(data_this_cycle));
   endaction
   action
      let data_this_cycle = packet_in_wire;
      Vector#(16, Bit#(1)) buff_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(112, Bit#(1)) unchanged = takeAt(16, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) curr_mask = takeAt(144, unpack(byteSwap(pack(ipv4_mask.first))));
      Vector#(16, Bit#(1)) curr_meta = takeAt(144, unpack(byteSwap(pack(ipv4_meta.first))));
      let masked_data = pack(buff_data) & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      let nextState = compute_next_state(ipv4_meta.first.protocol);
      $display("(%0d) compute_next_state ", $time, fshow(ipv4_meta.first.protocol));
      $display("(%0d) Goto ", $time, fshow(nextState));
      if (nextState == StateDeparseUdp) begin
         data_this_cycle.data = {pack(unchanged), pack(curr_data)};
         deparse_udp_fifo.enq(data_this_cycle);
      end
      ipv4_meta.deq;
      ipv4_mask.deq;
      state <= nextState;
   endaction
   endseq;

   FSM fsm_deparse_ipv4 <- mkFSM(deparse_ipv4);
   rule start_fsm if (start_wire);
      fsm_deparse_ipv4.start;
   endrule
   rule clear_fsm if (clear_wire);
      fsm_deparse_ipv4.abort;
   endrule
   method Action start();
      start_wire.send();
   endmethod
   method Action clear();
      clear_wire.send();
   endmethod
   interface deparse_ethernet = toPut(deparse_ethernet_fifo);
   interface deparse_udp = toGet(deparse_udp_fifo);
endmodule

interface DeparseUdp;
   interface Put#(EtherData) deparse_ipv4;
   interface Get#(EtherData) deparse_paxos;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparseUdp#(Reg#(DeparserState) state,
                          FIFOF#(EtherData) datain,
                          FIFOF#(EtherData) dataout,
                          FIFOF#(UdpT) udp_meta,
                          FIFOF#(UdpT) udp_mask)
                          (DeparseUdp);

   let verbose = False;
   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_ipv4_fifo <- mkBypassFIFOF;
   FIFO#(EtherData) deparse_paxos_fifo <- mkFIFO;

   PulseWire start_wire <- mkPulseWire();
   PulseWire clear_wire <- mkPulseWire();

   function DeparserState compute_next_state(Bit#(16) dstPort);
       DeparserState nextState = StateDeparseIdle;
       case (byteSwap(dstPort)) matches
           'h8888: begin
               nextState=StateDeparsePaxos;
           end
           default: begin
               nextState=StateDeparseIdle;
           end
       endcase
       return nextState;
   endfunction

   Stmt deparse_udp =
   seq
   action
      let data_this_cycle <- toGet(deparse_ipv4_fifo).get;
      Vector#(16, Bit#(1)) prev_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(64, Bit#(1)) udp_data = takeAt(16, unpack(data_this_cycle.data));
      Vector#(48, Bit#(1)) unchanged = takeAt(80, unpack(data_this_cycle.data));
      Vector#(64, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(udp_meta.first))));
      Vector#(64, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(udp_mask.first))));
      let masked_data = pack(udp_data) & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      let nextState = compute_next_state(udp_meta.first.dstPort);
      if (verbose) $display("(%0d) udp_meta.dstport=", $time, fshow(udp_meta.first.dstPort));
      if (verbose) $display("(%0d) Goto ", $time, fshow(nextState));
      if (nextState == StateDeparsePaxos) begin
         data_this_cycle.data = {pack(unchanged), pack(curr_data), pack(prev_data)};
         deparse_paxos_fifo.enq(data_this_cycle);
      end
      udp_meta.deq;
      udp_mask.deq;
      state <= nextState;
   endaction
   endseq;

   FSM fsm_deparse_udp <- mkFSM(deparse_udp);
   rule start_fsm if (start_wire);
      fsm_deparse_udp.start();
   endrule
   rule clear_fsm if (clear_wire);
      fsm_deparse_udp.abort();
   endrule
   method Action start();
      start_wire.send();
   endmethod
   method Action clear();
      clear_wire.send();
   endmethod
   interface deparse_ipv4 = toPut(deparse_ipv4_fifo);
   interface deparse_paxos = toGet(deparse_paxos_fifo);
endmodule

interface DeparsePaxos;
   interface Put#(EtherData) deparse_udp;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparsePaxos#(Reg#(DeparserState) state,
                            FIFOF#(EtherData) datain,
                            FIFOF#(EtherData) dataout,
                            FIFOF#(PaxosT) paxos_meta,
                            FIFOF#(PaxosT) paxos_mask)
                            (DeparsePaxos);

   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_udp_fifo <- mkBypassFIFOF;

   PulseWire start_wire <- mkPulseWire();
   PulseWire clear_wire <- mkPulseWire();

   function Bit#(128) apply_metadata(Integer offset, Bit#(128) field, PaxosT data, PaxosT mask);
      Vector#(128, Bit#(1)) curr_meta = takeAt(offset, unpack(byteSwap(pack(data))));
      Vector#(128, Bit#(1)) curr_mask = takeAt(offset, unpack(byteSwap(pack(mask))));
      return (field & pack(curr_mask)) | pack(curr_meta);
   endfunction

   rule load_packet if (state == StateDeparsePaxos && !deparse_udp_fifo.notEmpty());
       let data_current <- toGet(datain).get;
       packet_in_wire <= data_current;
       $display("(%0d) Paxos: ", $time, fshow(data_current));
   endrule

   Stmt deparse_paxos =
   seq
   action
      let data_this_cycle <- toGet(deparse_udp_fifo).get;
      Vector#(80, Bit#(1)) prev_data = takeAt(0, unpack(pack(data_this_cycle.data)));
      Vector#(48, Bit#(1)) last_data = takeAt(80, unpack(pack(data_this_cycle.data)));
      Vector#(48, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(paxos_meta.first))));
      Vector#(48, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(paxos_mask.first))));
      let masked_data = pack(last_data) & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      data_this_cycle.data = {curr_data, pack(prev_data)};
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(48, data_this_cycle.data, paxos_meta.first, paxos_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(176, data_this_cycle.data, paxos_meta.first, paxos_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      //let out = apply_metadata(304, data_this_cycle, paxos_meta.first, paxos_mask.first);
      Vector#(48, Bit#(1)) curr_meta = takeAt(304, unpack(byteSwap(pack(paxos_meta.first))));
      Vector#(48, Bit#(1)) curr_mask = takeAt(304, unpack(byteSwap(pack(paxos_mask.first))));
      Vector#(48, Bit#(1)) data = takeAt(0, unpack(pack(data_this_cycle.data)));
      Vector#(80, Bit#(1)) payload = takeAt(48, unpack(pack(data_this_cycle.data)));
      let out = (pack(data) & pack(curr_mask)) | pack(curr_meta);
      data_this_cycle.data = { pack(payload), out };
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
      paxos_meta.deq;
      paxos_mask.deq;
      state <= StateDeparseIdle;
   endaction
   endseq;
   FSM fsm_deparse_paxos <- mkFSM(deparse_paxos);
   rule start_fsm if (start_wire);
       fsm_deparse_paxos.start;
   endrule
   rule clear_fsm if (clear_wire);
       fsm_deparse_paxos.abort;
   endrule
   method Action start();
       start_wire.send();
   endmethod
   method Action clear();
       clear_wire.send();
   endmethod

   interface deparse_udp = toPut(deparse_udp_fifo);
endmodule

interface DeparseIpv6;
   interface Put#(EtherData) deparse_ethernet;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparseIpv6#(Reg#(DeparserState) state,
                           FIFOF#(EtherData) datain,
                           FIFOF#(EtherData) dataout,
                           FIFOF#(Ipv6T) ipv6_meta,
                           FIFOF#(Ipv6T) ipv6_mask)
                           (DeparseIpv6);
   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_ethernet_fifo <- mkBypassFIFOF;
   PulseWire start_wire <- mkPulseWire;
   PulseWire clear_wire <- mkPulseWire;

   function Bit#(128) apply_metadata(Integer offset, Bit#(128) field, Ipv6T data, Ipv6T mask);
      Vector#(128, Bit#(1)) curr_meta = takeAt(offset, unpack(byteSwap(pack(data))));
      Vector#(128, Bit#(1)) curr_mask = takeAt(offset, unpack(byteSwap(pack(mask))));
      return (field & pack(curr_mask)) | pack(curr_meta);
   endfunction

   rule load_packet if (state == StateDeparseIpv6 && !deparse_ethernet_fifo.notEmpty());
      let data_current <- toGet(datain).get;
      packet_in_wire <= data_current;
      $display("(%0d) IPv6: ", $time, fshow(data_current));
   endrule

   Stmt deparse_ipv6 =
   seq
   action
      let data_this_cycle <- toGet(deparse_ethernet_fifo).get;
      Vector#(112, Bit#(1)) last_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) data = takeAt(112, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(ipv6_meta.first))));
      Vector#(16, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(ipv6_meta.first))));
      let masked_data = pack(data) & pack(curr_mask);
      let out_data = masked_data | pack(curr_meta);
      $display("(%0d) IPv6: ", $time, fshow(data_this_cycle));
      data_this_cycle.data = {out_data, pack(last_data)};
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(16, data_this_cycle.data, ipv6_meta.first, ipv6_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(144, data_this_cycle.data, ipv6_meta.first, ipv6_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      Vector#(48, Bit#(1)) curr_meta = takeAt(272, unpack(byteSwap(pack(ipv6_meta.first))));
      Vector#(48, Bit#(1)) curr_mask = takeAt(272, unpack(byteSwap(pack(ipv6_mask.first))));
      Vector#(48, Bit#(1)) data = takeAt(0, unpack(pack(data_this_cycle.data)));
      Vector#(80, Bit#(1)) payload = takeAt(48, unpack(pack(data_this_cycle.data)));
      let out = (pack(data) & pack(curr_mask)) | pack(curr_meta);
      data_this_cycle.data = { pack(payload), out };
      dataout.enq(data_this_cycle);
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      ipv6_meta.deq;
      ipv6_mask.deq;
      state <= StateDeparseIdle;
   endaction
   endseq;
   FSM fsm_deparse_ipv6 <- mkFSM(deparse_ipv6);
   rule start_fsm if (start_wire);
       fsm_deparse_ipv6.start;
   endrule
   rule clear_fsm if (clear_wire);
       fsm_deparse_ipv6.abort;
   endrule
   method Action start();
       start_wire.send();
   endmethod
   method Action clear();
       clear_wire.send();
   endmethod
   interface deparse_ethernet = toPut(deparse_ethernet_fifo);
endmodule

interface Deparser;
   interface PipeIn#(MetadataT) metadata;
   interface PktWriteServer writeServer;
   interface PktWriteClient writeClient;
   method DeparserPerfRec read_perf_info;
endinterface

typedef 4 PortMax;
(* synthesize *)
module mkDeparser(Deparser);
   let verbose = False;
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(EtherData) data_out_fifo <- mkFIFOF;
   FIFOF#(MetadataT) metadata_in_fifo <- mkFIFOF;

   Reg#(Bool) started <- mkReg(False);
   Wire#(Bool) start_fsm <- mkDWire(False);
   Reg#(DeparserState) curr_state <- mkReg(StateDeparseIdle);

   Vector#(PortMax, FIFOF#(DeparserState)) deparse_state_in_fifo <- replicateM(mkGFIFOF(False, True));
   FIFOF#(DeparserState) deparse_state_out_fifo <- mkFIFOF;

   FIFOF#(EthernetT) ethernet_meta_fifo <- mkFIFOF;
   FIFOF#(Ipv4T) ipv4_meta_fifo <- mkFIFOF;
   FIFOF#(UdpT) udp_meta_fifo <- mkFIFOF;
   FIFOF#(PaxosT) paxos_meta_fifo <- mkFIFOF;
   FIFOF#(Ipv6T) ipv6_meta_fifo <- mkFIFOF;

   FIFOF#(EthernetT) ethernet_mask_fifo <- mkFIFOF;
   FIFOF#(Ipv4T) ipv4_mask_fifo <- mkFIFOF;
   FIFOF#(UdpT) udp_mask_fifo <- mkFIFOF;
   FIFOF#(PaxosT) paxos_mask_fifo <- mkFIFOF;
   FIFOF#(Ipv6T) ipv6_mask_fifo <- mkFIFOF;

   Reg#(Bit#(32)) clk_cnt <- mkReg(0);
   Reg#(Bit#(32)) deparser_start_time <- mkReg(0);
   Reg#(Bit#(32)) deparser_end_time <- mkReg(0);
   rule clockrule;
      clk_cnt <= clk_cnt + 1;
   endrule

   (* fire_when_enabled *)
   rule arbitrate_deparse_state;
      Bool sentOne = False;
      for (Integer port = 0; port < valueOf(PortMax); port = port+1) begin
         if (!sentOne && deparse_state_in_fifo[port].notEmpty()) begin
            DeparserState state <- toGet(deparse_state_in_fifo[port]).get();
            sentOne = True;
            $display("(%0d) xxx arbitrate %h", $time, port);
            deparse_state_out_fifo.enq(state);
         end
      end
   endrule

   rule get_metadata;
      let v <- toGet(metadata_in_fifo).get;
      let ethernet = toEthernet(v);
      match {.data, .mask} = ethernet;
      ethernet_meta_fifo.enq(data);
      ethernet_mask_fifo.enq(mask);

      let ipv4 = toIpv4(v);
      match {.ipv4_data, .ipv4_mask} = ipv4;
      if (verbose) $display("(%0d) ipv4 meta", $time, fshow(ipv4));
      ipv4_meta_fifo.enq(ipv4_data);
      ipv4_mask_fifo.enq(ipv4_mask);

      let udp = toUdp(v);
      match {.udp_data, .udp_mask} = udp;
      udp_meta_fifo.enq(udp_data);
      udp_mask_fifo.enq(udp_mask);

      //let ipv6 = toIpv6(v);
      //if (ipv6 matches tagged Valid {.data, .mask}) begin
      //   ipv6_meta_fifo.enq(data);
      //   ipv6_mask_fifo.enq(mask);
      //end

      let paxos = toPaxos(v);
      match {.paxos_data, .paxos_mask} = paxos;
      paxos_meta_fifo.enq(paxos_data);
      paxos_mask_fifo.enq(paxos_mask);
   endrule

   Empty init_state <- mkStateDeparseIdle(curr_state, data_in_fifo, data_out_fifo, start_fsm);
   DeparseEthernet deparse_ethernet <- mkStateDeparseEthernet(curr_state, data_in_fifo, data_out_fifo, ethernet_meta_fifo, ethernet_mask_fifo);
   //DeparseArp deparse_arp <- mkStateDeparseArp(curr_state, data_in_fifo);
   DeparseIpv4 deparse_ipv4 <- mkStateDeparseIpv4(curr_state, data_in_fifo, data_out_fifo, ipv4_meta_fifo, ipv4_mask_fifo);
   DeparseIpv6 deparse_ipv6 <- mkStateDeparseIpv6(curr_state, data_in_fifo, data_out_fifo, ipv6_meta_fifo, ipv6_mask_fifo);
   DeparseUdp deparse_udp <- mkStateDeparseUdp(curr_state, data_in_fifo, data_out_fifo, udp_meta_fifo, udp_mask_fifo);
   DeparsePaxos deparse_paxos <- mkStateDeparsePaxos(curr_state, data_in_fifo, data_out_fifo, paxos_meta_fifo, paxos_mask_fifo);

   //mkConnection(deparse_arp.deparse_ethernet, deparse_ethernet.deparse_arp);
   mkConnection(deparse_ipv4.deparse_ethernet, deparse_ethernet.deparse_ipv4);
   mkConnection(deparse_ipv6.deparse_ethernet, deparse_ethernet.deparse_ipv6);
   mkConnection(deparse_udp.deparse_ipv4, deparse_ipv4.deparse_udp);
   mkConnection(deparse_paxos.deparse_udp, deparse_udp.deparse_paxos);

   rule start if (start_fsm);
      if (!started) begin
         deparse_ethernet.start;
         //deparse_arp.start;
         deparse_ipv4.start;
         //deparse_ipv6.start;
         deparse_udp.start;
         deparse_paxos.start;
         started <= True;
         deparser_start_time <= clk_cnt;
      end
   endrule

   rule clear if (!start_fsm && curr_state == StateDeparseIdle);
      if (started) begin
         deparse_ethernet.clear;
         //deparse_arp.clear;
         deparse_ipv4.clear;
         //deparse_ipv6.clear;
         deparse_udp.clear;
         deparse_paxos.clear;
         started <= False;
         deparser_end_time <= clk_cnt;
      end
   endrule

   interface PktWriteServer writeServer;
      interface writeData = toPut(data_in_fifo);
   endinterface
   interface PktWriteClient writeClient;
      interface writeData = toGet(data_out_fifo);
   endinterface
   interface metadata = toPipeIn(metadata_in_fifo);
   method DeparserPerfRec read_perf_info;
      return DeparserPerfRec {
         deparser_start_time: deparser_start_time,
         deparser_end_time: deparser_end_time
      };
   endmethod
endmodule

// Copyright (c) 2016 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.
import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import DbgDefs::*;
import FIFO::*;
import FIFOF::*;
import FShow::*;
import GetPut::*;
import List::*;
import StmtFSM::*;
import SpecialFIFOs::*;
import Vector::*;
import Pipe::*;
import Ethernet::*;
import PaxosTypes::*;
import PacketBuffer::*;
import P4Types::*;
import Utils::*;

typedef enum {
   StateDeparseIdle,
   StateDeparseEthernet,
   StateDeparseArp,
   StateDeparseIpv4,
   StateDeparseIpv6,
   StateDeparseUdp,
   StateDeparsePaxos
} DeparserState deriving (Bits, Eq, FShow);

function Tuple2#(EthernetT, EthernetT) toEthernet(MetadataT meta);
   EthernetT data = defaultValue;
   EthernetT mask = defaultMask;
   data.dstAddr = fromMaybe(?, meta.dstAddr);
   mask.dstAddr = 0;
   data.etherType = fromMaybe(?, meta.etherType);
   mask.etherType = 0;
   return tuple2(data, mask);
endfunction

function Tuple2#(Ipv4T, Ipv4T) toIpv4(MetadataT meta);
   Ipv4T ipv4 = defaultValue;
   Ipv4T mask = defaultMask;
   ipv4.protocol = fromMaybe(?, meta.protocol);
   mask.protocol = 0;
   return tuple2(ipv4, mask);
endfunction

function Tuple2#(UdpT, UdpT) toUdp(MetadataT meta);
   UdpT udp = defaultValue;
   UdpT mask = defaultMask;
   udp.dstPort = fromMaybe(?, meta.dstPort);
   mask.dstPort = 0;
   udp.checksum = 0;
   mask.checksum = 0;
   return tuple2(udp, mask);
endfunction

function Tuple2#(Ipv6T, Ipv6T) toIpv6(MetadataT meta);
   Ipv6T ipv6 = defaultValue;
   Ipv6T mask = defaultMask;
   return tuple2(ipv6, mask);
endfunction

//
function Tuple2#(PaxosT, PaxosT) toPaxos(MetadataT meta);
   PaxosT paxos = defaultValue;
   PaxosT mask = defaultMask;
   paxos.inst = fromMaybe(?, meta.paxos$inst);
   mask.inst = 0;
   paxos.rnd = fromMaybe(?, meta.paxos$rnd);
   mask.rnd = 0;
   paxos.vrnd = fromMaybe(?, meta.paxos$vrnd);
   mask.vrnd = 0;
   paxos.acptid = fromMaybe(?, meta.paxos$acptid);
   mask.acptid = 0;
   paxos.paxosval = fromMaybe(?, meta.paxos$paxosval);
   mask.paxosval = 0;
   return tuple2(paxos, mask);
endfunction

module mkStateDeparseIdle#(Reg#(DeparserState) state, FIFOF#(EtherData) datain, FIFOF#(EtherData) dataout, Wire#(Bool) start_fsm)(Empty);

   rule load_packet if (state == StateDeparseIdle);
      let v = datain.first;
      if (v.sop) begin
         state <= StateDeparseEthernet;
         start_fsm <= True;
         $display("(%0d) Deparse Ethernet Start", $time);
      end
      else begin
         datain.deq;
         dataout.enq(v);
         $display("(%0d) payload ", $time, fshow(v));
         start_fsm <= False;
      end
   endrule
endmodule

interface DeparseEthernet;
   interface Get#(EtherData) deparse_arp;
   interface Get#(EtherData) deparse_ipv4;
   interface Get#(EtherData) deparse_ipv6;
   method Action start;
   method Action clear;
endinterface

module mkStateDeparseEthernet#(Reg#(DeparserState) state,
                               FIFOF#(EtherData) datain,
                               FIFOF#(EtherData) dataout,
                               FIFOF#(EthernetT) ethernet_meta,
                               FIFOF#(EthernetT) ethernet_mask)
                               (DeparseEthernet);
   let verbose = False;
   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFO#(EtherData) parse_arp_fifo <- mkFIFO;
   FIFO#(EtherData) parse_ipv4_fifo <- mkFIFO;
   FIFO#(EtherData) parse_ipv6_fifo <- mkFIFO;

   PulseWire start_wire <- mkPulseWire;
   PulseWire clear_wire <- mkPulseWire;

   function DeparserState compute_next_state(Bit#(16) etherType);
       DeparserState nextState = StateDeparseIdle;
       case (byteSwap(etherType)) matches
           'h806: begin
               nextState=StateDeparseArp;
           end
           'h800: begin
               nextState=StateDeparseIpv4;
           end
           'h86dd: begin
               nextState=StateDeparseIpv6;
           end
           default: begin
               nextState=StateDeparseIdle;
           end
       endcase
       return nextState;
   endfunction

   rule load_packet if (state == StateDeparseEthernet);
      let data_current <- toGet(datain).get;
      packet_in_wire <= data_current;
      $display("(%0d) Ether: ", $time, fshow(data_current));
   endrule

   Stmt deparse_ethernet =
   seq
   action
      let data_this_cycle = packet_in_wire;
      let metadata = ethernet_meta.first;
      let mask = ethernet_mask.first;
      Vector#(128, Bit#(1)) dataVec = unpack(data_this_cycle.data);
      Vector#(112, Bit#(1)) hdr = takeAt(0, dataVec);
      Vector#(16, Bit#(1)) unchanged = takeAt(112, dataVec);
      EthernetT ethernet = unpack(pack(hdr));
      let nextState = compute_next_state(metadata.etherType);
      if (verbose) $display("(%0d) Eth: %h", $time, metadata.etherType);
      if (verbose) $display("(%0d) Goto ", $time, fshow(nextState));
      data_this_cycle.data = {pack(unchanged), pack(hdr)};
      if (nextState == StateDeparseArp) begin
         parse_arp_fifo.enq(data_this_cycle);
      end
      else if (nextState == StateDeparseIpv4) begin
         parse_ipv4_fifo.enq(data_this_cycle);
      end
      else if (nextState == StateDeparseIpv6) begin
         parse_ipv6_fifo.enq(data_this_cycle);
      end
      state <= nextState;
      ethernet_meta.deq;
      ethernet_mask.deq;
   endaction
   endseq;

   FSM fsm_deparse_ethernet <- mkFSM(deparse_ethernet);
   rule start_fsm if (start_wire);
      fsm_deparse_ethernet.start;
   endrule
   rule clear_fsm if (clear_wire);
      fsm_deparse_ethernet.abort;
   endrule
   method Action start();
      start_wire.send();
   endmethod
   method Action clear();
      clear_wire.send();
   endmethod
   interface deparse_arp = toGet(parse_arp_fifo);
   interface deparse_ipv4 = toGet(parse_ipv4_fifo);
   interface deparse_ipv6 = toGet(parse_ipv6_fifo);
endmodule

interface DeparseIpv4;
   interface Put#(EtherData) deparse_ethernet;
   interface Get#(EtherData) deparse_udp;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparseIpv4#(Reg#(DeparserState) state,
                           FIFOF#(EtherData) datain,
                           FIFOF#(EtherData) dataout,
                           FIFOF#(Ipv4T) ipv4_meta,
                           FIFOF#(Ipv4T) ipv4_mask)
                           (DeparseIpv4);

   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_ethernet_fifo <- mkBypassFIFOF;
   FIFO#(EtherData) deparse_udp_fifo <- mkFIFO;
   PulseWire start_wire <- mkPulseWire();
   PulseWire clear_wire <- mkPulseWire();

   function DeparserState compute_next_state(Bit#(8) protocol);
       DeparserState nextState = StateDeparseIdle;
       case (byteSwap(protocol)) matches
           'h11: begin
               nextState=StateDeparseUdp;
           end
           default: begin
               nextState=StateDeparseIdle;
           end
       endcase
       return nextState;
   endfunction

   rule load_packet if (state == StateDeparseIpv4 && !deparse_ethernet_fifo.notEmpty());
       let data_current <- toGet(datain).get;
       packet_in_wire <= data_current;
       $display("(%0d) IPv4: ", $time, fshow(data_current));
   endrule

   Stmt deparse_ipv4 =
   seq
   action
      let data_this_cycle <- toGet(deparse_ethernet_fifo).get;
      Vector#(112, Bit#(1)) last_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) data = takeAt(112, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(ipv4_meta.first))));
      Vector#(16, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(ipv4_mask.first))));
      let masked_data = pack(data) & pack(curr_mask);
      let out_data = masked_data | pack(curr_meta);
      $display("(%0d) IPv4: [1] ", $time, fshow(data_this_cycle), " meta=%h, mask=%h", curr_mask, curr_meta);
      data_this_cycle.data = {out_data, pack(last_data)};
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      Vector#(128, Bit#(1)) curr_meta = takeAt(16, unpack(byteSwap(pack(ipv4_meta.first))));
      Vector#(128, Bit#(1)) curr_mask = takeAt(16, unpack(byteSwap(pack(ipv4_mask.first))));
      let masked_data = data_this_cycle.data & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      data_this_cycle.data = curr_data;
      dataout.enq(data_this_cycle);
      $display("(%0d) IPv4: [2] ", $time, fshow(data_this_cycle));
   endaction
   action
      let data_this_cycle = packet_in_wire;
      Vector#(16, Bit#(1)) buff_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(112, Bit#(1)) unchanged = takeAt(16, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) curr_mask = takeAt(144, unpack(byteSwap(pack(ipv4_mask.first))));
      Vector#(16, Bit#(1)) curr_meta = takeAt(144, unpack(byteSwap(pack(ipv4_meta.first))));
      let masked_data = pack(buff_data) & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      let nextState = compute_next_state(ipv4_meta.first.protocol);
      $display("(%0d) compute_next_state ", $time, fshow(ipv4_meta.first.protocol));
      $display("(%0d) Goto ", $time, fshow(nextState));
      if (nextState == StateDeparseUdp) begin
         data_this_cycle.data = {pack(unchanged), pack(curr_data)};
         deparse_udp_fifo.enq(data_this_cycle);
      end
      ipv4_meta.deq;
      ipv4_mask.deq;
      state <= nextState;
   endaction
   endseq;

   FSM fsm_deparse_ipv4 <- mkFSM(deparse_ipv4);
   rule start_fsm if (start_wire);
      fsm_deparse_ipv4.start;
   endrule
   rule clear_fsm if (clear_wire);
      fsm_deparse_ipv4.abort;
   endrule
   method Action start();
      start_wire.send();
   endmethod
   method Action clear();
      clear_wire.send();
   endmethod
   interface deparse_ethernet = toPut(deparse_ethernet_fifo);
   interface deparse_udp = toGet(deparse_udp_fifo);
endmodule

interface DeparseUdp;
   interface Put#(EtherData) deparse_ipv4;
   interface Get#(EtherData) deparse_paxos;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparseUdp#(Reg#(DeparserState) state,
                          FIFOF#(EtherData) datain,
                          FIFOF#(EtherData) dataout,
                          FIFOF#(UdpT) udp_meta,
                          FIFOF#(UdpT) udp_mask)
                          (DeparseUdp);

   let verbose = False;
   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_ipv4_fifo <- mkBypassFIFOF;
   FIFO#(EtherData) deparse_paxos_fifo <- mkFIFO;

   PulseWire start_wire <- mkPulseWire();
   PulseWire clear_wire <- mkPulseWire();

   function DeparserState compute_next_state(Bit#(16) dstPort);
       DeparserState nextState = StateDeparseIdle;
       case (byteSwap(dstPort)) matches
           'h8888: begin
               nextState=StateDeparsePaxos;
           end
           default: begin
               nextState=StateDeparseIdle;
           end
       endcase
       return nextState;
   endfunction

   Stmt deparse_udp =
   seq
   action
      let data_this_cycle <- toGet(deparse_ipv4_fifo).get;
      Vector#(80, Bit#(1)) unsent = takeAt(0, unpack(data_this_cycle.data));
      Vector#(48, Bit#(1)) unchanged = takeAt(80, unpack(data_this_cycle.data));
      let nextState = compute_next_state(udp_meta.first.dstPort);
      if (verbose) $display("(%0d) udp_meta.dstport=", $time, fshow(udp_meta.first.dstPort));
      if (verbose) $display("(%0d) Goto ", $time, fshow(nextState));
      if (nextState == StateDeparsePaxos) begin
         data_this_cycle.data = {pack(unchanged), pack(unsent)};
         deparse_paxos_fifo.enq(data_this_cycle);
      end
      udp_meta.deq;
      udp_mask.deq;
      state <= nextState;
   endaction
   endseq;

   FSM fsm_deparse_udp <- mkFSM(deparse_udp);
   rule start_fsm if (start_wire);
      fsm_deparse_udp.start();
   endrule
   rule clear_fsm if (clear_wire);
      fsm_deparse_udp.abort();
   endrule
   method Action start();
      start_wire.send();
   endmethod
   method Action clear();
      clear_wire.send();
   endmethod
   interface deparse_ipv4 = toPut(deparse_ipv4_fifo);
   interface deparse_paxos = toGet(deparse_paxos_fifo);
endmodule

interface DeparsePaxos;
   interface Put#(EtherData) deparse_udp;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparsePaxos#(Reg#(DeparserState) state,
                            FIFOF#(EtherData) datain,
                            FIFOF#(EtherData) dataout,
                            FIFOF#(PaxosT) paxos_meta,
                            FIFOF#(PaxosT) paxos_mask)
                            (DeparsePaxos);

   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_udp_fifo <- mkBypassFIFOF;

   PulseWire start_wire <- mkPulseWire();
   PulseWire clear_wire <- mkPulseWire();

   function Bit#(128) apply_metadata(Integer offset, Bit#(128) field, PaxosT data, PaxosT mask);
      Vector#(128, Bit#(1)) curr_meta = takeAt(offset, unpack(byteSwap(pack(data))));
      Vector#(128, Bit#(1)) curr_mask = takeAt(offset, unpack(byteSwap(pack(mask))));
      return (field & pack(curr_mask)) | pack(curr_meta);
   endfunction

   rule load_packet if (state == StateDeparsePaxos && !deparse_udp_fifo.notEmpty());
       let data_current <- toGet(datain).get;
       packet_in_wire <= data_current;
       $display("(%0d) Paxos: ", $time, fshow(data_current));
   endrule

   Stmt deparse_paxos =
   seq
   action
      let data_this_cycle <- toGet(deparse_udp_fifo).get;
      Vector#(80, Bit#(1)) prev_data = takeAt(0, unpack(pack(data_this_cycle.data)));
      Vector#(48, Bit#(1)) last_data = takeAt(80, unpack(pack(data_this_cycle.data)));
      Vector#(48, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(paxos_meta.first))));
      Vector#(48, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(paxos_mask.first))));
      let masked_data = pack(last_data) & pack(curr_mask);
      let curr_data = masked_data | pack(curr_meta);
      data_this_cycle.data = {curr_data, pack(prev_data)};
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(48, data_this_cycle.data, paxos_meta.first, paxos_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(176, data_this_cycle.data, paxos_meta.first, paxos_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      //let out = apply_metadata(304, data_this_cycle, paxos_meta.first, paxos_mask.first);
      Vector#(48, Bit#(1)) curr_meta = takeAt(304, unpack(byteSwap(pack(paxos_meta.first))));
      Vector#(48, Bit#(1)) curr_mask = takeAt(304, unpack(byteSwap(pack(paxos_mask.first))));
      Vector#(48, Bit#(1)) data = takeAt(0, unpack(pack(data_this_cycle.data)));
      Vector#(80, Bit#(1)) payload = takeAt(48, unpack(pack(data_this_cycle.data)));
      let out = (pack(data) & pack(curr_mask)) | pack(curr_meta);
      data_this_cycle.data = { pack(payload), out };
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
      paxos_meta.deq;
      paxos_mask.deq;
      state <= StateDeparseIdle;
   endaction
   endseq;
   FSM fsm_deparse_paxos <- mkFSM(deparse_paxos);
   rule start_fsm if (start_wire);
       fsm_deparse_paxos.start;
   endrule
   rule clear_fsm if (clear_wire);
       fsm_deparse_paxos.abort;
   endrule
   method Action start();
       start_wire.send();
   endmethod
   method Action clear();
       clear_wire.send();
   endmethod

   interface deparse_udp = toPut(deparse_udp_fifo);
endmodule

interface DeparseIpv6;
   interface Put#(EtherData) deparse_ethernet;
   method Action start;
   method Action clear;
endinterface
module mkStateDeparseIpv6#(Reg#(DeparserState) state,
                           FIFOF#(EtherData) datain,
                           FIFOF#(EtherData) dataout,
                           FIFOF#(Ipv6T) ipv6_meta,
                           FIFOF#(Ipv6T) ipv6_mask)
                           (DeparseIpv6);
   Wire#(EtherData) packet_in_wire <- mkDWire(defaultValue);
   FIFOF#(EtherData) deparse_ethernet_fifo <- mkBypassFIFOF;
   PulseWire start_wire <- mkPulseWire;
   PulseWire clear_wire <- mkPulseWire;

   function Bit#(128) apply_metadata(Integer offset, Bit#(128) field, Ipv6T data, Ipv6T mask);
      Vector#(128, Bit#(1)) curr_meta = takeAt(offset, unpack(byteSwap(pack(data))));
      Vector#(128, Bit#(1)) curr_mask = takeAt(offset, unpack(byteSwap(pack(mask))));
      return (field & pack(curr_mask)) | pack(curr_meta);
   endfunction

   rule load_packet if (state == StateDeparseIpv6 && !deparse_ethernet_fifo.notEmpty());
      let data_current <- toGet(datain).get;
      packet_in_wire <= data_current;
      $display("(%0d) IPv6: ", $time, fshow(data_current));
   endrule

   Stmt deparse_ipv6 =
   seq
   action
      let data_this_cycle <- toGet(deparse_ethernet_fifo).get;
      Vector#(112, Bit#(1)) last_data = takeAt(0, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) data = takeAt(112, unpack(data_this_cycle.data));
      Vector#(16, Bit#(1)) curr_meta = takeAt(0, unpack(byteSwap(pack(ipv6_meta.first))));
      Vector#(16, Bit#(1)) curr_mask = takeAt(0, unpack(byteSwap(pack(ipv6_meta.first))));
      let masked_data = pack(data) & pack(curr_mask);
      let out_data = masked_data | pack(curr_meta);
      $display("(%0d) IPv6: ", $time, fshow(data_this_cycle));
      data_this_cycle.data = {out_data, pack(last_data)};
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(16, data_this_cycle.data, ipv6_meta.first, ipv6_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      let out = apply_metadata(144, data_this_cycle.data, ipv6_meta.first, ipv6_mask.first);
      data_this_cycle.data = out;
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      dataout.enq(data_this_cycle);
   endaction
   action
      let data_this_cycle = packet_in_wire;
      Vector#(48, Bit#(1)) curr_meta = takeAt(272, unpack(byteSwap(pack(ipv6_meta.first))));
      Vector#(48, Bit#(1)) curr_mask = takeAt(272, unpack(byteSwap(pack(ipv6_mask.first))));
      Vector#(48, Bit#(1)) data = takeAt(0, unpack(pack(data_this_cycle.data)));
      Vector#(80, Bit#(1)) payload = takeAt(48, unpack(pack(data_this_cycle.data)));
      let out = (pack(data) & pack(curr_mask)) | pack(curr_meta);
      data_this_cycle.data = { pack(payload), out };
      dataout.enq(data_this_cycle);
      $display("(%0d) dataout ", $time, fshow(data_this_cycle));
      ipv6_meta.deq;
      ipv6_mask.deq;
      state <= StateDeparseIdle;
   endaction
   endseq;
   FSM fsm_deparse_ipv6 <- mkFSM(deparse_ipv6);
   rule start_fsm if (start_wire);
       fsm_deparse_ipv6.start;
   endrule
   rule clear_fsm if (clear_wire);
       fsm_deparse_ipv6.abort;
   endrule
   method Action start();
       start_wire.send();
   endmethod
   method Action clear();
       clear_wire.send();
   endmethod
   interface deparse_ethernet = toPut(deparse_ethernet_fifo);
endmodule

interface Deparser;
   interface PipeIn#(MetadataT) metadata;
   interface PktWriteServer writeServer;
   interface PktWriteClient writeClient;
   method DeparserPerfRec read_perf_info;
endinterface

typedef 4 PortMax;
(* synthesize *)
module mkDeparser(Deparser);
   let verbose = False;
   FIFOF#(EtherData) data_in_fifo <- mkSizedFIFOF(4);
   FIFOF#(EtherData) data_out_fifo <- mkFIFOF;
   FIFOF#(MetadataT) metadata_in_fifo <- mkFIFOF;

   Reg#(Bool) started <- mkReg(False);
   Wire#(Bool) start_fsm <- mkDWire(False);
   Reg#(DeparserState) curr_state <- mkReg(StateDeparseIdle);

   Vector#(PortMax, FIFOF#(DeparserState)) deparse_state_in_fifo <- replicateM(mkGFIFOF(False, True));
   FIFOF#(DeparserState) deparse_state_out_fifo <- mkFIFOF;

   FIFOF#(EthernetT) ethernet_meta_fifo <- mkFIFOF;
   FIFOF#(Ipv4T) ipv4_meta_fifo <- mkFIFOF;
   FIFOF#(UdpT) udp_meta_fifo <- mkFIFOF;
   FIFOF#(PaxosT) paxos_meta_fifo <- mkFIFOF;
   FIFOF#(Ipv6T) ipv6_meta_fifo <- mkFIFOF;

   FIFOF#(EthernetT) ethernet_mask_fifo <- mkFIFOF;
   FIFOF#(Ipv4T) ipv4_mask_fifo <- mkFIFOF;
   FIFOF#(UdpT) udp_mask_fifo <- mkFIFOF;
   FIFOF#(PaxosT) paxos_mask_fifo <- mkFIFOF;
   FIFOF#(Ipv6T) ipv6_mask_fifo <- mkFIFOF;

   Reg#(Bit#(32)) clk_cnt <- mkReg(0);
   Reg#(Bit#(32)) deparser_start_time <- mkReg(0);
   Reg#(Bit#(32)) deparser_end_time <- mkReg(0);
   rule clockrule;
      clk_cnt <= clk_cnt + 1;
   endrule

   (* fire_when_enabled *)
   rule arbitrate_deparse_state;
      Bool sentOne = False;
      for (Integer port = 0; port < valueOf(PortMax); port = port+1) begin
         if (!sentOne && deparse_state_in_fifo[port].notEmpty()) begin
            DeparserState state <- toGet(deparse_state_in_fifo[port]).get();
            sentOne = True;
            $display("(%0d) xxx arbitrate %h", $time, port);
            deparse_state_out_fifo.enq(state);
         end
      end
   endrule

   rule get_metadata;
      let v <- toGet(metadata_in_fifo).get;
      let ethernet = toEthernet(v);
      match {.data, .mask} = ethernet;
      ethernet_meta_fifo.enq(data);
      ethernet_mask_fifo.enq(mask);

      let ipv4 = toIpv4(v);
      match {.ipv4_data, .ipv4_mask} = ipv4;
      if (verbose) $display("(%0d) ipv4 meta", $time, fshow(ipv4));
      ipv4_meta_fifo.enq(ipv4_data);
      ipv4_mask_fifo.enq(ipv4_mask);

      let udp = toUdp(v);
      match {.udp_data, .udp_mask} = udp;
      udp_meta_fifo.enq(udp_data);
      udp_mask_fifo.enq(udp_mask);

      //let ipv6 = toIpv6(v);
      //if (ipv6 matches tagged Valid {.data, .mask}) begin
      //   ipv6_meta_fifo.enq(data);
      //   ipv6_mask_fifo.enq(mask);
      //end

      let paxos = toPaxos(v);
      match {.paxos_data, .paxos_mask} = paxos;
      paxos_meta_fifo.enq(paxos_data);
      paxos_mask_fifo.enq(paxos_mask);
   endrule

   Empty init_state <- mkStateDeparseIdle(curr_state, data_in_fifo, data_out_fifo, start_fsm);
   DeparseEthernet deparse_ethernet <- mkStateDeparseEthernet(curr_state, data_in_fifo, data_out_fifo, ethernet_meta_fifo, ethernet_mask_fifo);
   //DeparseArp deparse_arp <- mkStateDeparseArp(curr_state, data_in_fifo);
   DeparseIpv4 deparse_ipv4 <- mkStateDeparseIpv4(curr_state, data_in_fifo, data_out_fifo, ipv4_meta_fifo, ipv4_mask_fifo);
   DeparseIpv6 deparse_ipv6 <- mkStateDeparseIpv6(curr_state, data_in_fifo, data_out_fifo, ipv6_meta_fifo, ipv6_mask_fifo);
   DeparseUdp deparse_udp <- mkStateDeparseUdp(curr_state, data_in_fifo, data_out_fifo, udp_meta_fifo, udp_mask_fifo);
   DeparsePaxos deparse_paxos <- mkStateDeparsePaxos(curr_state, data_in_fifo, data_out_fifo, paxos_meta_fifo, paxos_mask_fifo);

   //mkConnection(deparse_arp.deparse_ethernet, deparse_ethernet.deparse_arp);
   mkConnection(deparse_ipv4.deparse_ethernet, deparse_ethernet.deparse_ipv4);
   mkConnection(deparse_ipv6.deparse_ethernet, deparse_ethernet.deparse_ipv6);
   mkConnection(deparse_udp.deparse_ipv4, deparse_ipv4.deparse_udp);
   mkConnection(deparse_paxos.deparse_udp, deparse_udp.deparse_paxos);

   rule start if (start_fsm);
      if (!started) begin
         deparse_ethernet.start;
         //deparse_arp.start;
         deparse_ipv4.start;
         //deparse_ipv6.start;
         deparse_udp.start;
         deparse_paxos.start;
         started <= True;
         deparser_start_time <= clk_cnt;
      end
   endrule

   rule clear if (!start_fsm && curr_state == StateDeparseIdle);
      if (started) begin
         deparse_ethernet.clear;
         //deparse_arp.clear;
         deparse_ipv4.clear;
         //deparse_ipv6.clear;
         deparse_udp.clear;
         deparse_paxos.clear;
         started <= False;
         deparser_end_time <= clk_cnt;
      end
   endrule

   interface PktWriteServer writeServer;
      interface writeData = toPut(data_in_fifo);
   endinterface
   interface PktWriteClient writeClient;
      interface writeData = toGet(data_out_fifo);
   endinterface
   interface metadata = toPipeIn(metadata_in_fifo);
   method DeparserPerfRec read_perf_info;
      return DeparserPerfRec {
         deparser_start_time: deparser_start_time,
         deparser_end_time: deparser_end_time
      };
   endmethod
endmodule


THis was a copy of the standard Bluespec I2C, it is in the Misc
library, so not needed here.

We might rewrite it someday, as this one doesn't support burst mode
I think,