mute deparser debug message

mute deparser debug message

// 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 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 P4Utils::*;

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;
   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;
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;

   (* 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;
      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;
      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);
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 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 P4Utils::*;

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;
   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 = True;
   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 = True;
   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;
endinterface

typedef 4 PortMax;
(* synthesize *)
module mkDeparser(Deparser);
   let verbose = True;
   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;

   (* 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;
      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;
      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);
endmodule


xsim prefers "TRUE" rather than 1 for FIRST_WORD_FALL_THROUGH

// Copyright (c) 2015 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 Clocks::*;
import Vector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import CBus::*; // extendNP and truncateNP

`include "ConnectalProjectConfig.bsv"
import Arith::*;
import ConnectalClocks::*;

`ifdef SIMULATION
`ifdef BOARD_xsim
`define USE_XILINX_MACRO
`endif // xsim
`else // not SIMULATION
`ifdef XILINX
`define USE_XILINX_MACRO
`endif // XILINX
`endif // not SIMULATION

`ifdef USE_XILINX_MACRO
(* always_ready, always_enabled *)
interface X7FifoSyncMacro#(numeric type data_width);
   method Bit#(1) empty();
   method Bit#(1) full();
   method Action din(Bit#(data_width) v);
   method Action wren(Bit#(1) wren);
   method Bit#(data_width) dout();
   method Action rden(Bit#(1) rden);
   method Bit#(9) wrcount();
   method Bit#(9) rdcount();
endinterface

import "BVI" FIFO_DUALCLOCK_MACRO =
module  vmkBramFifo#(String fifo_size, Clock wrClock, Reset wrReset, Clock rdClock, Reset rdReset)(X7FifoSyncMacro#(data_width));
`ifndef BSV_POSITIVE_RESET
   let positiveReset <- mkPositiveReset(10, wrReset, wrClock);
   let fifoReset = positiveReset.positiveReset;
`else
   let fifoReset = wrReset;
`endif
   parameter DEVICE = "7SERIES";
   parameter DATA_WIDTH = valueOf(data_width);
   parameter FIFO_SIZE = fifo_size;
   parameter FIRST_WORD_FALL_THROUGH = "TRUE";
   default_clock wrClock(WRCLK) = wrClock;
   no_reset;
   input_reset wrReset(RST) = fifoReset;
   input_clock rdClock(RDCLK) = rdClock;
   method EMPTY empty() clocked_by (rdClock) reset_by (wrReset);
   method FULL full() clocked_by (wrClock) reset_by (wrReset);
   method din(DI) enable ((*inhigh*)EN_di) clocked_by (wrClock) reset_by (wrReset);
   method wren(WREN) enable ((*inhigh*)EN_wren) clocked_by (wrClock) reset_by (wrReset);
   method DO dout() clocked_by (rdClock) reset_by (wrReset);
   method rden(RDEN) enable ((*inhigh*)EN_rden) clocked_by (rdClock) reset_by (wrReset);
   // wrcount and rdcount ports are needed for xsim
   method WRCOUNT wrcount() clocked_by (wrClock) reset_by (wrReset);
   method RDCOUNT rdcount() clocked_by (rdClock) reset_by (wrReset);
   schedule (empty, full, dout, din, wren, rden, wrcount, rdcount) CF (empty, full, dout, din, wren, rden, wrcount, rdcount);
endmodule

module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   String fifo_size = "18Kb";
   Vector#(TDiv#(sizet,36),X7FifoSyncMacro#(36)) fifos <- replicateM(vmkBramFifo(fifo_size, srcClock, srcReset, dstClock, dstReset));
   Wire#(Bit#(1)) rdenWire <- mkDWire(0, clocked_by dstClock, reset_by dstReset);
   Wire#(Bit#(1)) wrenWire <- mkDWire(0, clocked_by srcClock, reset_by srcReset);
   Vector#(TDiv#(sizet,36),Wire#(Bit#(36))) dinWires <- replicateM(mkDWire(0, clocked_by srcClock, reset_by srcReset));

   for (Integer i = 0; i < valueOf(TDiv#(sizet,36)); i = i+1) begin
      Reg#(Bit#(9)) rdcount <- mkReg(0, clocked_by dstClock, reset_by dstReset);
      Reg#(Bit#(9)) wrcount <- mkReg(0, clocked_by srcClock, reset_by srcReset);
      rule rdenRule;
	 fifos[i].rden(rdenWire);
      endrule
      rule wrenRule;
	 fifos[i].wren(wrenWire);
      endrule
      rule inputs;
	 fifos[i].din(dinWires[i]);
      endrule
      rule countrds;
	 rdcount <= fifos[i].rdcount();
      endrule
      rule countwrs;
	 wrcount <= fifos[i].wrcount();
      endrule
   end

   method t first() if (fifos[0].empty == 0);
      function Bit#(36) fifoFirst(Integer i); return fifos[i].dout(); endfunction
      Vector#(TDiv#(sizet,36), Bit#(36)) v = genWith(fifoFirst);
      return unpack(truncateNP(pack(v)));
   endmethod
   method Action deq() if (fifos[0].empty == 0);
      rdenWire <= 1;
   endmethod
   method notEmpty = (fifos[0].empty == 0);
   method Action enq(t v) if (fifos[0].full == 0);
      Vector#(TDiv#(sizet,36), Bit#(36)) vs = unpack(extendNP(pack(v)));
      Vector#(TDiv#(sizet,36), Integer) indices = genVector();
      function Action fifoEnq(Integer i); action dinWires[i] <= vs[i]; endaction endfunction
      mapM_(fifoEnq, indices);
      wrenWire <= 1;
   endmethod
   method notFull = (fifos[0].full == 0);
endmodule

module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkDualClockBramFIFOF(srcClock, srcReset, dstClock, dstReset);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule

`else // compatibility mode
module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
   method notFull = syncFifo.notFull;
   method notEmpty = syncFifo.notEmpty;
endmodule
module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule
`endif

// Copyright (c) 2015 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 Clocks::*;
import Vector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import CBus::*; // extendNP and truncateNP

`include "ConnectalProjectConfig.bsv"
import Arith::*;
import ConnectalClocks::*;

`ifdef SIMULATION
`ifdef BOARD_xsim
`define USE_XILINX_MACRO
`endif // xsim
`else // not SIMULATION
`ifdef XILINX
`define USE_XILINX_MACRO
`endif // XILINX
`endif // not SIMULATION

`ifdef USE_XILINX_MACRO
(* always_ready, always_enabled *)
interface X7FifoSyncMacro#(numeric type data_width);
   method Bit#(1) empty();
   method Bit#(1) full();
   method Action din(Bit#(data_width) v);
   method Action wren(Bit#(1) wren);
   method Bit#(data_width) dout();
   method Action rden(Bit#(1) rden);
   method Bit#(9) wrcount();
   method Bit#(9) rdcount();
endinterface

import "BVI" FIFO_DUALCLOCK_MACRO =
module  vmkBramFifo#(String fifo_size, Clock wrClock, Reset wrReset, Clock rdClock, Reset rdReset)(X7FifoSyncMacro#(data_width));
`ifndef BSV_POSITIVE_RESET
   let positiveReset <- mkPositiveReset(10, wrReset, wrClock);
   let fifoReset = positiveReset.positiveReset;
`else
   let fifoReset = wrReset;
`endif
   parameter DEVICE = "7SERIES";
   parameter DATA_WIDTH = valueOf(data_width);
   parameter FIFO_SIZE = fifo_size;
   parameter FIRST_WORD_FALL_THROUGH = 1;
   default_clock wrClock(WRCLK) = wrClock;
   no_reset;
   input_reset wrReset(RST) = fifoReset;
   input_clock rdClock(RDCLK) = rdClock;
   method EMPTY empty() clocked_by (rdClock) reset_by (wrReset);
   method FULL full() clocked_by (wrClock) reset_by (wrReset);
   method din(DI) enable ((*inhigh*)EN_di) clocked_by (wrClock) reset_by (wrReset);
   method wren(WREN) enable ((*inhigh*)EN_wren) clocked_by (wrClock) reset_by (wrReset);
   method DO dout() clocked_by (rdClock) reset_by (wrReset);
   method rden(RDEN) enable ((*inhigh*)EN_rden) clocked_by (rdClock) reset_by (wrReset);
   // wrcount and rdcount ports are needed for xsim
   method WRCOUNT wrcount() clocked_by (wrClock) reset_by (wrReset);
   method RDCOUNT rdcount() clocked_by (rdClock) reset_by (wrReset);
   schedule (empty, full, dout, din, wren, rden, wrcount, rdcount) CF (empty, full, dout, din, wren, rden, wrcount, rdcount);
endmodule

module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   String fifo_size = "18Kb";
   Vector#(TDiv#(sizet,36),X7FifoSyncMacro#(36)) fifos <- replicateM(vmkBramFifo(fifo_size, srcClock, srcReset, dstClock, dstReset));
   Wire#(Bit#(1)) rdenWire <- mkDWire(0, clocked_by dstClock, reset_by dstReset);
   Wire#(Bit#(1)) wrenWire <- mkDWire(0, clocked_by srcClock, reset_by srcReset);
   Vector#(TDiv#(sizet,36),Wire#(Bit#(36))) dinWires <- replicateM(mkDWire(0, clocked_by srcClock, reset_by srcReset));

   for (Integer i = 0; i < valueOf(TDiv#(sizet,36)); i = i+1) begin
      Reg#(Bit#(9)) rdcount <- mkReg(0, clocked_by dstClock, reset_by dstReset);
      Reg#(Bit#(9)) wrcount <- mkReg(0, clocked_by srcClock, reset_by srcReset);
      rule rdenRule;
	 fifos[i].rden(rdenWire);
      endrule
      rule wrenRule;
	 fifos[i].wren(wrenWire);
      endrule
      rule inputs;
	 fifos[i].din(dinWires[i]);
      endrule
      rule countrds;
	 rdcount <= fifos[i].rdcount();
      endrule
      rule countwrs;
	 wrcount <= fifos[i].wrcount();
      endrule
   end

   method t first() if (fifos[0].empty == 0);
      function Bit#(36) fifoFirst(Integer i); return fifos[i].dout(); endfunction
      Vector#(TDiv#(sizet,36), Bit#(36)) v = genWith(fifoFirst);
      return unpack(truncateNP(pack(v)));
   endmethod
   method Action deq() if (fifos[0].empty == 0);
      rdenWire <= 1;
   endmethod
   method notEmpty = (fifos[0].empty == 0);
   method Action enq(t v) if (fifos[0].full == 0);
      Vector#(TDiv#(sizet,36), Bit#(36)) vs = unpack(extendNP(pack(v)));
      Vector#(TDiv#(sizet,36), Integer) indices = genVector();
      function Action fifoEnq(Integer i); action dinWires[i] <= vs[i]; endaction endfunction
      mapM_(fifoEnq, indices);
      wrenWire <= 1;
   endmethod
   method notFull = (fifos[0].full == 0);
endmodule

module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkDualClockBramFIFOF(srcClock, srcReset, dstClock, dstReset);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule

`else // compatibility mode
module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
   method notFull = syncFifo.notFull;
   method notEmpty = syncFifo.notEmpty;
endmodule
module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule
`endif


12 bit identifiers -> 6 bit identifiers

12 bit identifiers -> 6 bit identifiers

Change-Id: Ia79029148005e1b511d8deb5bd9c9e251e15d293

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

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

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

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

import Vector            :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import AxiClientServer   :: *;
import Leds              :: *;
import Top               :: *;

import "BDPI" function Action      initPortal(Bit#(32) d);
import "BDPI" function Bool                    writeReq();
import "BDPI" function ActionValue#(Bit#(32)) writeAddr();
import "BDPI" function ActionValue#(Bit#(32)) writeData();
import "BDPI" function Bool                     readReq();
import "BDPI" function ActionValue#(Bit#(32))  readAddr();
import "BDPI" function Action        readData(Bit#(32) d);

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

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

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

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

typedef (function Module#(PortalTop#(nmasters, dsz, ipins)) mkpt()) MkPortalTop#(numeric type nmasters, numeric type dsz, type ipins);

module [Module] mkBsimTopFromPortal#(MkPortalTop#(nmasters,dsz,ipins) constructor)(Empty)
   provisos (SelectBsimRdmaReadWrite#(dsz));

   Integer nmasters = valueOf(nmasters);
   let top <- constructor();
   Axi3Client#(40,dsz,TDiv#(dsz,8),6) master = ?;
   if (nmasters > 0) begin
      master = top.m_axi[0];

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

      Reg#(Bool) inited <- mkReg(False);
      rule initialize(!inited);
	 inited <= True;
	 init_pareff();
      endrule

      Reg#(Bit#(40)) readAddr <- mkReg(0);
      Reg#(Bit#(5))  readLen <- mkReg(0);
      Reg#(Bit#(6)) readId <- mkReg(0);
      Reg#(Bit#(40)) writeAddr <- mkReg(0);
      Reg#(Bit#(5))  writeLen <- mkReg(0);
      Reg#(Bit#(6)) writeId <- mkReg(0);

      rule req_ar if (readLen == 0);
	 let req <- master.req_ar.get();
	 Bit#(5) rlen = extend(req.len)+1;
	 $display("req_ar: addr=%h len=%d", req.address, rlen);
	 readAddr <= req.address;
	 readLen <= rlen;
	 readId <= req.id;
      endrule
      rule read_resp if (readLen > 0);
	 let handle = readAddr[39:32];
	 let addr = readAddr[31:0];
	 Bit#(dsz) v <- rw.read_pareff(extend(handle), addr);
	 $display("read_resp: handle=%d addr=%h v=%h", handle, addr, v);
	 readLen <= readLen - 1;
	 readAddr <= readAddr + fromInteger(valueOf(dsz)/8);
	 let resp = Axi3ReadResponse { data: v, resp: 0, last: pack(readLen == 1), id: readId};
	 master.resp_read.put(resp);
      endrule

      rule req_aw if (writeLen == 0);
	 let req <- master.req_aw.get();
	 Bit#(5) wlen = extend(req.len)+1;
	 $display("req_aw: addr=%h len=%d", req.address, wlen);
	 writeAddr <= req.address;
	 writeLen <= wlen;
	 writeId <= req.id;
      endrule

      FIFO#(Axi3WriteResponse#(6)) bFifo <- mkFIFO();

      rule write_resp if (writeLen > 0);
	 let handle = writeAddr[39:32];
	 let addr = writeAddr[31:0];
	 let resp <- master.resp_write.get();
	 rw.write_pareff(extend(handle), addr, resp.data);
	 $display("write_resp: handle=%d addr=%h v=%h", handle, addr, resp.data);
	 writeLen <= writeLen - 1;
	 writeAddr <= writeAddr + fromInteger(valueOf(dsz)/8);
	 if (writeLen == 1)
	    bFifo.enq(Axi3WriteResponse { id: writeId, resp: 0 });
      endrule

      rule resp_b;
	 let resp = bFifo.first();
	 bFifo.deq();
	 master.resp_b.put(resp);
      endrule
   end

   let wf <- mkPipelineFIFO;
   let init_seq = (action
		      initPortal(0);
		      initPortal(1);
		      initPortal(2);
		      initPortal(3);
		      initPortal(4);
		      initPortal(5);
		      initPortal(6);
		      initPortal(7);
                   endaction);
   let init_fsm <- mkOnce(init_seq);

   (* descending_urgency = "rdResp, rdReq" *)
   rule init_rule;
      init_fsm.start;
   endrule
   rule wrReq (writeReq());
      let wa <- writeAddr;
      let wd <- writeData;
      top.ctrl.req_aw.put(Axi3WriteRequest { address: wa, len: 0, size: axiBusSize(32), id: 0, prot: 0, burst: 1, cache: 'b11, qos: 0, lock: 0 });
      wf.enq(wd);
   endrule
   rule wrData;
      wf.deq;
      top.ctrl.resp_write.put(Axi3WriteData { data: wf.first, id: 0, last: 1 });
   endrule
   rule wrB;
      let resp <- top.ctrl.resp_b.get();
   endrule
   rule rdReq (readReq());
      let ra <- readAddr;
	 top.ctrl.req_ar.put(Axi3ReadRequest { address: ra, len: 0, size: axiBusSize(32), id: 0, prot: 0, burst: 1, cache: 'b11, qos: 0, lock: 0 });
   endrule
   rule rdResp;
      let rd <- top.ctrl.resp_read.get();
      readData(rd.data);
   endrule
endmodule

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

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

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

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

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

import Vector            :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import AxiClientServer   :: *;
import Leds              :: *;
import Top               :: *;

import "BDPI" function Action      initPortal(Bit#(32) d);
import "BDPI" function Bool                    writeReq();
import "BDPI" function ActionValue#(Bit#(32)) writeAddr();
import "BDPI" function ActionValue#(Bit#(32)) writeData();
import "BDPI" function Bool                     readReq();
import "BDPI" function ActionValue#(Bit#(32))  readAddr();
import "BDPI" function Action        readData(Bit#(32) d);

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

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

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

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

typedef (function Module#(PortalTop#(nmasters, dsz, ipins)) mkpt()) MkPortalTop#(numeric type nmasters, numeric type dsz, type ipins);

module [Module] mkBsimTopFromPortal#(MkPortalTop#(nmasters,dsz,ipins) constructor)(Empty)
   provisos (SelectBsimRdmaReadWrite#(dsz));

   Integer nmasters = valueOf(nmasters);
   let top <- constructor();
   Axi3Client#(40,dsz,TDiv#(dsz,8),6) master = ?;
   if (nmasters > 0) begin
      master = top.m_axi[0];

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

      Reg#(Bool) inited <- mkReg(False);
      rule initialize(!inited);
	 inited <= True;
	 init_pareff();
      endrule

      Reg#(Bit#(40)) readAddr <- mkReg(0);
      Reg#(Bit#(5))  readLen <- mkReg(0);
      Reg#(Bit#(12)) readId <- mkReg(0);
      Reg#(Bit#(40)) writeAddr <- mkReg(0);
      Reg#(Bit#(5))  writeLen <- mkReg(0);
      Reg#(Bit#(12)) writeId <- mkReg(0);

      rule req_ar if (readLen == 0);
	 let req <- master.req_ar.get();
	 Bit#(5) rlen = extend(req.len)+1;
	 $display("req_ar: addr=%h len=%d", req.address, rlen);
	 readAddr <= req.address;
	 readLen <= rlen;
	 readId <= req.id;
      endrule
      rule read_resp if (readLen > 0);
	 let handle = readAddr[39:32];
	 let addr = readAddr[31:0];
	 Bit#(dsz) v <- rw.read_pareff(extend(handle), addr);
	 $display("read_resp: handle=%d addr=%h v=%h", handle, addr, v);
	 readLen <= readLen - 1;
	 readAddr <= readAddr + fromInteger(valueOf(dsz)/8);
	 let resp = Axi3ReadResponse { data: v, resp: 0, last: pack(readLen == 1), id: readId};
	 master.resp_read.put(resp);
      endrule

      rule req_aw if (writeLen == 0);
	 let req <- master.req_aw.get();
	 Bit#(5) wlen = extend(req.len)+1;
	 $display("req_aw: addr=%h len=%d", req.address, wlen);
	 writeAddr <= req.address;
	 writeLen <= wlen;
	 writeId <= req.id;
      endrule

      FIFO#(Axi3WriteResponse#(12)) bFifo <- mkFIFO();

      rule write_resp if (writeLen > 0);
	 let handle = writeAddr[39:32];
	 let addr = writeAddr[31:0];
	 let resp <- master.resp_write.get();
	 rw.write_pareff(extend(handle), addr, resp.data);
	 $display("write_resp: handle=%d addr=%h v=%h", handle, addr, resp.data);
	 writeLen <= writeLen - 1;
	 writeAddr <= writeAddr + fromInteger(valueOf(dsz)/8);
	 if (writeLen == 1)
	    bFifo.enq(Axi3WriteResponse { id: writeId, resp: 0 });
      endrule

      rule resp_b;
	 let resp = bFifo.first();
	 bFifo.deq();
	 master.resp_b.put(resp);
      endrule
   end

   let wf <- mkPipelineFIFO;
   let init_seq = (action
		      initPortal(0);
		      initPortal(1);
		      initPortal(2);
		      initPortal(3);
		      initPortal(4);
		      initPortal(5);
		      initPortal(6);
		      initPortal(7);
                   endaction);
   let init_fsm <- mkOnce(init_seq);

   (* descending_urgency = "rdResp, rdReq" *)
   rule init_rule;
      init_fsm.start;
   endrule
   rule wrReq (writeReq());
      let wa <- writeAddr;
      let wd <- writeData;
      top.ctrl.req_aw.put(Axi3WriteRequest { address: wa, len: 0, size: axiBusSize(32), id: 0, prot: 0, burst: 1, cache: 'b11, qos: 0, lock: 0 });
      wf.enq(wd);
   endrule
   rule wrData;
      wf.deq;
      top.ctrl.resp_write.put(Axi3WriteData { data: wf.first, id: 0, last: 1 });
   endrule
   rule wrB;
      let resp <- top.ctrl.resp_b.get();
   endrule
   rule rdReq (readReq());
      let ra <- readAddr;
	 top.ctrl.req_ar.put(Axi3ReadRequest { address: ra, len: 0, size: axiBusSize(32), id: 0, prot: 0, burst: 1, cache: 'b11, qos: 0, lock: 0 });
   endrule
   rule rdResp;
      let rd <- top.ctrl.resp_read.get();
      readData(rd.data);
   endrule
endmodule

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