enable other trace readout mechanisms for mkConnectionWithTrace(ps7, ...)

// 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 Clocks::*;
import DefaultValue::*;
import GetPut::*;
import Connectable::*;
import ConnectableWithTrace::*;
import Bscan::*;
import Vector::*;
import PPS7LIB::*;
import Portal::*;
import AxiMasterSlave::*;
import AxiDma::*;
import XilinxCells::*;
import ConnectalXilinxCells::*;
import ConnectalClocks::*;
import AxiBits::*;
import AxiGather::*;

(* always_ready, always_enabled *)
interface Bidir#(numeric type data_width);
    method Action             i(Bit#(data_width) v);
    method Bit#(data_width)   o();
    method Bit#(data_width)   t();
endinterface

interface PS7LIB;
`ifdef PS7EXTENDED
    interface Vector#(2, Pps7Emiocan)  can;
    interface Vector#(4, Pps7Dma)  dma;
    interface Vector#(2, Pps7Emioenet) enet;
    interface Pps7Event            event_;
//    interface Vector#(4,Pps7Fclk_clktrig)fclk_clktrig;
//    interface Pps7Fpga             fpga;
    interface Pps7Ftmd             ftmd;
    interface Pps7Ftmt             ftmt;
    interface Pps7Emiopjtag            pjtag;
    interface Vector#(2, Pps7Emiosdio) sdio;
    interface Vector#(2, Pps7Emiospi)  spi;
//    interface Pps7Sram             sram;
    interface Pps7Emiotrace            trace;
    interface Vector#(2, Pps7Emiottc)  ttc;
    interface Vector#(2, Pps7Emiouart) uart;
    interface Vector#(2, Pps7Emiousb)  usb;
    interface Pps7Emiowdt              wdt;
`endif
    interface Pps7Ddr              ddr;
    method Bit#(4)     fclkclk();
    method Action      fclkclktrign(Bit#(4) v);
    method Bit#(4)     fclkresetn();
    method Action      fpgaidlen(Bit#(1) v);
    interface Pps7Emiogpio             gpio;
    interface Vector#(2, Pps7Emioi2c)  i2c;
    interface Pps7Irq              irq;
    interface Inout#(Bit#(54))     mio;
    interface Pps7Ps               ps;

    interface Vector#(2, AxiMasterCommon#(32,32,12)) m_axi_gp;
    interface Vector#(2, AxiSlaveCommon#(32,32,6,Empty)) s_axi_gp;
    interface Vector#(4, AxiSlaveCommon#(32,64,6,HPType)) s_axi_hp;
    interface AxiSlaveCommon#(32,64,3,ACPType) s_axi_acp;
endinterface

module mkPS7LIB#(Clock axi_clock, Reset axi_reset)(PS7LIB);
    PPS7LIB foo <- mkPPS7LIB(
        axi_clock, axi_clock, axi_clock, axi_clock, axi_clock, axi_clock, axi_clock, axi_clock,
        axi_clock, axi_reset, axi_reset, axi_reset, axi_reset, axi_reset, axi_reset, axi_reset,
        axi_reset, axi_reset);
`ifdef PS7EXTENDED
    Vector#(2, Pps7Emiocan)     vcan;
    Vector#(4, Pps7Dma)     vdma;
    Vector#(2, Pps7Emioenet)     venet;
    Vector#(2, Pps7Emiosdio)     vsdio;
    Vector#(2, Pps7Emiospi)     vspi;
    Vector#(2, Pps7Emiottc)     vttc;
    Vector#(2, Pps7Emiouart)     vuart;
    Vector#(2, Pps7Emiousb)     vusb;
`endif
    Vector#(2, Pps7Emioi2c)     vi2c;
    Vector#(2, AxiMasterCommon#(32,32,12)) vtopm_axi_gp;
    Vector#(2, AxiSlaveCommon#(32,32,6,Empty)) vtops_axi_gp;
    Vector#(1, AxiSlaveCommon#(32,64,3,ACPType)) vtops_axi_acp;
    Vector#(4, AxiSlaveCommon#(32,64,6,HPType)) vtops_axi_hp;

`ifdef PS7EXTENDED
    vcan[0] = foo.emiocan0;
    vcan[1] = foo.emiocan1;
    vdma[0] = foo.dma0;
    vdma[1] = foo.dma1;
    vdma[2] = foo.dma2;
    vdma[3] = foo.dma3;
    venet[0] = foo.emioenet0;
    venet[1] = foo.emioenet1;
    vsdio[0] = foo.emiosdio0;
    vsdio[1] = foo.emiosdio1;
    vspi[0] = foo.emiospi0;
    vspi[1] = foo.emiospi1;
    vttc[0] = foo.emiottc0;
    vttc[1] = foo.emiottc1;
    vuart[0] = foo.emiouart0;
    vuart[1] = foo.emiouart1;
    vusb[0] = foo.emiousb0;
    vusb[1] = foo.emiousb1;
`endif
    vi2c[0] = foo.emioi2c0;
    vi2c[1] = foo.emioi2c1;
    vtopm_axi_gp[0] <- mkAxi3MasterGather(foo.maxigp0, clocked_by axi_clock, reset_by axi_reset);
    vtopm_axi_gp[1] <- mkAxi3MasterGather(foo.maxigp1, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_gp[0] <- mkAxi3SlaveGather(foo.saxigp0, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_gp[1] <- mkAxi3SlaveGather(foo.saxigp1, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_acp[0] <- mkAxi3SlaveGather(foo.saxiacp, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[0] <- mkAxi3SlaveGather(foo.saxihp0, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[1] <- mkAxi3SlaveGather(foo.saxihp1, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[2] <- mkAxi3SlaveGather(foo.saxihp2, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[3] <- mkAxi3SlaveGather(foo.saxihp3, clocked_by axi_clock, reset_by axi_reset);
    Wire#(Bit#(1)) fpgaidlenw <- mkDWire(1);
    rule fpgaidle;
       foo.fpgaidlen(fpgaidlenw);
    endrule
    rule misc;
       foo.emiosramintin(0);
       // UG585 "fclkclktrign is currently not supported and must be tied to ground"
       foo.fclkclktrign(0);
    endrule

`ifdef PS7EXTENDED
    interface Pps7Can can = vcan;
    interface Pps7Dma     dma = vdma;
    interface Pps7Enet     enet = venet;
    interface Pps7Sdio    sdio = vsdio;
    interface Pps7Spi    spi = vspi;
    interface Pps7Ttc    ttc = vttc;
    interface Pps7Uart    uart = vuart;
    interface Pps7Usb    usb = vusb;
    interface Pps7Event     event_ = foo.event_;
//    interface Pps7Fpga     fpga = foo.fpga;
    interface Pps7Ftmd     ftmd = foo.ftmd;
    interface Pps7Ftmt     ftmt = foo.ftmt;
    interface Pps7Pjtag     pjtag = foo.emiopjtag;
//    interface Pps7Sram     sram = foo.sram;
    interface Pps7Emiotrace     trace = foo.emiotrace;
    interface Pps7Wdt     wdt = foo.emiowdt;
`endif
    interface i2c = vi2c;
    interface ddr = foo.ddr;
    interface fclkclk = foo.fclkclk;
    interface fclkresetn = foo.fclkresetn;
    method Action      fclkclktrign(Bit#(4) v);
        foo.fclkclktrign(v);
    endmethod
    method Action      fpgaidlen(Bit#(1) v);
       fpgaidlenw <= v;
    endmethod
    interface gpio = foo.emiogpio;
    interface irq = foo.irq;
    interface mio = foo.mio;
    interface ps = foo.ps;

    interface m_axi_gp = vtopm_axi_gp;
    interface s_axi_gp = vtops_axi_gp;
    interface s_axi_hp = vtops_axi_hp;
    interface s_axi_acp = vtops_axi_acp[0];
endmodule

interface ZynqPins;
    (* prefix="DDR_Addr" *) interface Inout#(Bit#(15))     a;
    (* prefix="DDR_BankAddr" *) interface Inout#(Bit#(3))     ba;
    (* prefix="DDR_CAS_n" *) interface Inout#(Bit#(1))     casb;
    (* prefix="DDR_CKE" *) interface Inout#(Bit#(1))     cke;
    (* prefix="DDR_CS_n" *) interface Inout#(Bit#(1))     csb;
    (* prefix="DDR_Clk_n" *) interface Inout#(Bit#(1))     ckn;
    (* prefix="DDR_Clk_p" *) interface Inout#(Bit#(1))     ck;
    (* prefix="DDR_DM" *) interface Inout#(Bit#(4))     dm;
    (* prefix="DDR_DQ" *) interface Inout#(Bit#(32))     dq;
    (* prefix="DDR_DQS_n" *) interface Inout#(Bit#(4))     dqsn;
    (* prefix="DDR_DQS_p" *) interface Inout#(Bit#(4))     dqs;
    (* prefix="DDR_DRSTB" *) interface Inout#(Bit#(1))     drstb;
    (* prefix="DDR_ODT" *) interface Inout#(Bit#(1))     odt;
    (* prefix="DDR_RAS_n" *) interface Inout#(Bit#(1))     rasb;
    (* prefix="FIXED_IO_ddr_vrn" *) interface Inout#(Bit#(1))     vrn;
    (* prefix="FIXED_IO_ddr_vrp" *) interface Inout#(Bit#(1))     vrp;
    (* prefix="DDR_WEB" *) interface Inout#(Bit#(1))     web;
    (* prefix="MIO" *)
    interface Inout#(Bit#(54))       mio;
    (* prefix="FIXED_IO_ps" *)
    interface Pps7Ps ps;
endinterface

interface PS7;
    (* prefix="" *)
    interface ZynqPins pins;
    interface Vector#(2, AxiMasterCommon#(32,32,12))     m_axi_gp;
    interface Vector#(2, AxiSlaveCommon#(32,32,6,Empty)) s_axi_gp;
    interface Vector#(4, AxiSlaveCommon#(32,64,6,HPType))   s_axi_hp;
    interface Vector#(1, AxiSlaveCommon#(32,64,3,ACPType))   s_axi_acp;
    method Action                             interrupt(Bit#(1) v);
    interface Vector#(4, Clock) fclkclk;
    interface Vector#(4, Reset) fclkreset;
    interface Vector#(2, Pps7Emioi2c)  i2c;
    interface Clock derivedClock;
    interface Reset derivedReset;
`ifdef PS7EXTENDED
    interface Pps7Emiosdio emiosdio1;
`endif
endinterface

module mkPS7(PS7);
   // B2C converts a bit to a clock, enabling us to break the apparent cycle
   Vector#(4, B2C) b2c <- replicateM(mkB2C());

   // need the bufg here to reduce clock skew
   module mkBufferedClock#(Integer i)(Clock); let c <- mkClockBUFG(clocked_by b2c[i].c); return c; endmodule
   module mkBufferedReset#(Integer i)(Reset); let r <- mkResetBUFG(clocked_by b2c[i].c, reset_by b2c[i].r); return r; endmodule
   Vector#(4, Clock) fclk <- genWithM(mkBufferedClock);
   Vector#(4, Reset) freset <- genWithM(mkBufferedReset);

   Clock single_clock = fclk[0];
`ifdef ZYNQ_NO_RESET
   freset[0]          = noReset;
`endif
   let single_reset   = freset[0];

   ClockGenerator7Params clockParams = defaultValue;
   // input clock 200MHz for speed grade -2, 100MHz for speed grade -1
   // fpll needs to be in the range 600MHz - 1200MHz for either input clock
   //
   // fclkin = 1e9 / mainClockPeriod
   // fpll = 1e9 = mult_f * 1e9 / mainClockPeriod
   // mult_f = mainClockPeriod
   //
   // fclkout0 = 1e9 / divide_f = 1e9 / derivedClockPeriod
   // divide_f = derivedClockPeriod
   //
   clockParams.clkfbout_mult_f       = mainClockPeriod;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkin1_period      = mainClockPeriod;
   clockParams.clkout0_divide_f   = derivedClockPeriod;
   clockParams.clkout0_duty_cycle = 0.5;
   clockParams.clkout0_phase      = 0.0000;
   clockParams.clkout0_buffer     = True;
   clockParams.clkin_buffer = False;
   ClockGenerator7   clockGen <- mkClockGenerator7(clockParams, clocked_by single_clock, reset_by single_reset);
   let derived_clock = clockGen.clkout0;
   let derived_reset_unbuffered <- mkAsyncReset(2, single_reset, derived_clock);
   let derived_reset <- mkResetBUFG(clocked_by derived_clock, reset_by derived_reset_unbuffered);

   PS7LIB ps7 <- mkPS7LIB(single_clock, single_reset, clocked_by single_clock, reset_by single_reset);

   // this rule connects the fclkclk wires to the clock net via B2C
   for (Integer i = 0; i < 4; i = i + 1) begin
      ReadOnly#(Bit#(4)) fclkb;
      ReadOnly#(Bit#(4)) fclkresetnb;
      fclkb       <- mkNullCrossingWire(b2c[i].c, ps7.fclkclk);
      fclkresetnb <- mkNullCrossingWire(b2c[i].c, ps7.fclkresetn);
      rule b2c_rule1;
	 b2c[i].inputclock(fclkb[i]);
	 b2c[i].inputreset(fclkresetnb[i]);
      endrule
      rule issue_rule;
         ps7.s_axi_hp[i].extra.rdissuecap1en(0);
         ps7.s_axi_hp[i].extra.wrissuecap1en(0);
      endrule
   end

   IDELAYCTRL idel <- mkIDELAYCTRL(2, clocked_by fclk[3], reset_by freset[0]);

    rule arb_rule;
        ps7.ddr.arb(4'b0);
    endrule

`ifdef PS7EXTENDED
    interface Pps7Emiosdio emiosdio1 = ps7.sdio[1];
`endif
    interface ZynqPins pins;
    interface a = ps7.ddr.a;
    interface ba = ps7.ddr.ba;
    interface casb = ps7.ddr.casb;
    interface cke = ps7.ddr.cke;
    interface csb = ps7.ddr.csb;
    interface ckn = ps7.ddr.ckn;
    interface ck = ps7.ddr.ckp;
    interface dm = ps7.ddr.dm;
    interface dq = ps7.ddr.dq;
    interface dqsn = ps7.ddr.dqsn;
    interface dqs = ps7.ddr.dqsp;
    interface drstb = ps7.ddr.drstb;
    interface odt = ps7.ddr.odt;
    interface rasb = ps7.ddr.rasb;
    interface vrn = ps7.ddr.vrn;
    interface vrp = ps7.ddr.vrp;
    interface web = ps7.ddr.web;
    interface mio = ps7.mio;
    interface ps = ps7.ps;
    endinterface
    interface m_axi_gp = ps7.m_axi_gp;
    interface s_axi_gp = ps7.s_axi_gp;
    interface s_axi_hp = ps7.s_axi_hp;
    interface fclkclk = fclk;
    interface fclkreset = freset;
    interface derivedClock = derived_clock;
    interface derivedReset = derived_reset;
    method Action interrupt(Bit#(1) v);
        ps7.irq.f2p({19'b0, v});
    endmethod
    interface i2c = ps7.i2c;
   interface s_axi_acp = cons(ps7.s_axi_acp, nil);
endmodule

`ifdef USE_ACP
typedef 1 NumAcp;
`else
typedef 0 NumAcp;
`endif

instance ConnectableWithTrace#(PS7, ConnectalTop#(32,64,ipins,nMasters), traceType)
   provisos (ConnectableWithTrace::ConnectableWithTrace#(AxiMasterSlave::Axi3Master#(32,64,6),AxiMasterSlave::Axi3Slave#(32, 64, 6),traceType),
             ConnectableWithTrace::ConnectableWithTrace#(AxiMasterSlave::Axi3Master#(32,32,12),AxiMasterSlave::Axi3Slave#(32,32,12),traceType));
   module mkConnectionWithTrace#(PS7 ps7, ConnectalTop#(32,64,ipins,nMasters) top, traceType readout)(Empty)
      provisos (ConnectableWithTrace#(Axi3Master#(32,64,6), Axi3Slave#(32,64,6),traceType));

      Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(top.slave);
      mkConnectionWithTrace(ps7.m_axi_gp[0].client, ctrl, readout);

`ifdef USE_ACP
      begin
	 Axi3Master#(32,64,3) acp_m_axi <- mkAxiDmaMaster(top.masters[0]);
	 mkConnection(acp_m_axi, ps7.s_axi_acp[0].server);
      end
      rule acp_aruser;
	 ps7.s_axi_acp[0].extra.aruser(5'h1f);
      endrule
      rule acp_awuser;
	 ps7.s_axi_acp[0].extra.awuser(5'h1f);
      endrule
`endif
      module mkAxiMasterConnection#(Integer i)(Axi3Master#(32,64,6));
	 let m_axi <- mkAxiDmaMaster(top.masters[i+valueOf(NumAcp)]);
	 mkConnection(m_axi, ps7.s_axi_hp[i].server);
	 return m_axi;
      endmodule
      Vector#(TSub#(nMasters,NumAcp), Axi3Master#(32,64,6)) m_axis <- genWithM(mkAxiMasterConnection);

   endmodule
endinstance

// 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 Clocks::*;
import DefaultValue::*;
import GetPut::*;
import Connectable::*;
import ConnectableWithTrace::*;
import Bscan::*;
import Vector::*;
import PPS7LIB::*;
import Portal::*;
import AxiMasterSlave::*;
import AxiDma::*;
import XilinxCells::*;
import ConnectalXilinxCells::*;
import ConnectalClocks::*;
import AxiBits::*;
import AxiGather::*;

(* always_ready, always_enabled *)
interface Bidir#(numeric type data_width);
    method Action             i(Bit#(data_width) v);
    method Bit#(data_width)   o();
    method Bit#(data_width)   t();
endinterface

interface PS7LIB;
`ifdef PS7EXTENDED
    interface Vector#(2, Pps7Emiocan)  can;
    interface Vector#(4, Pps7Dma)  dma;
    interface Vector#(2, Pps7Emioenet) enet;
    interface Pps7Event            event_;
//    interface Vector#(4,Pps7Fclk_clktrig)fclk_clktrig;
//    interface Pps7Fpga             fpga;
    interface Pps7Ftmd             ftmd;
    interface Pps7Ftmt             ftmt;
    interface Pps7Emiopjtag            pjtag;
    interface Vector#(2, Pps7Emiosdio) sdio;
    interface Vector#(2, Pps7Emiospi)  spi;
//    interface Pps7Sram             sram;
    interface Pps7Emiotrace            trace;
    interface Vector#(2, Pps7Emiottc)  ttc;
    interface Vector#(2, Pps7Emiouart) uart;
    interface Vector#(2, Pps7Emiousb)  usb;
    interface Pps7Emiowdt              wdt;
`endif
    interface Pps7Ddr              ddr;
    method Bit#(4)     fclkclk();
    method Action      fclkclktrign(Bit#(4) v);
    method Bit#(4)     fclkresetn();
    method Action      fpgaidlen(Bit#(1) v);
    interface Pps7Emiogpio             gpio;
    interface Vector#(2, Pps7Emioi2c)  i2c;
    interface Pps7Irq              irq;
    interface Inout#(Bit#(54))     mio;
    interface Pps7Ps               ps;

    interface Vector#(2, AxiMasterCommon#(32,32,12)) m_axi_gp;
    interface Vector#(2, AxiSlaveCommon#(32,32,6,Empty)) s_axi_gp;
    interface Vector#(4, AxiSlaveCommon#(32,64,6,HPType)) s_axi_hp;
    interface AxiSlaveCommon#(32,64,3,ACPType) s_axi_acp;
endinterface

module mkPS7LIB#(Clock axi_clock, Reset axi_reset)(PS7LIB);
    PPS7LIB foo <- mkPPS7LIB(
        axi_clock, axi_clock, axi_clock, axi_clock, axi_clock, axi_clock, axi_clock, axi_clock,
        axi_clock, axi_reset, axi_reset, axi_reset, axi_reset, axi_reset, axi_reset, axi_reset,
        axi_reset, axi_reset);
`ifdef PS7EXTENDED
    Vector#(2, Pps7Emiocan)     vcan;
    Vector#(4, Pps7Dma)     vdma;
    Vector#(2, Pps7Emioenet)     venet;
    Vector#(2, Pps7Emiosdio)     vsdio;
    Vector#(2, Pps7Emiospi)     vspi;
    Vector#(2, Pps7Emiottc)     vttc;
    Vector#(2, Pps7Emiouart)     vuart;
    Vector#(2, Pps7Emiousb)     vusb;
`endif
    Vector#(2, Pps7Emioi2c)     vi2c;
    Vector#(2, AxiMasterCommon#(32,32,12)) vtopm_axi_gp;
    Vector#(2, AxiSlaveCommon#(32,32,6,Empty)) vtops_axi_gp;
    Vector#(1, AxiSlaveCommon#(32,64,3,ACPType)) vtops_axi_acp;
    Vector#(4, AxiSlaveCommon#(32,64,6,HPType)) vtops_axi_hp;

`ifdef PS7EXTENDED
    vcan[0] = foo.emiocan0;
    vcan[1] = foo.emiocan1;
    vdma[0] = foo.dma0;
    vdma[1] = foo.dma1;
    vdma[2] = foo.dma2;
    vdma[3] = foo.dma3;
    venet[0] = foo.emioenet0;
    venet[1] = foo.emioenet1;
    vsdio[0] = foo.emiosdio0;
    vsdio[1] = foo.emiosdio1;
    vspi[0] = foo.emiospi0;
    vspi[1] = foo.emiospi1;
    vttc[0] = foo.emiottc0;
    vttc[1] = foo.emiottc1;
    vuart[0] = foo.emiouart0;
    vuart[1] = foo.emiouart1;
    vusb[0] = foo.emiousb0;
    vusb[1] = foo.emiousb1;
`endif
    vi2c[0] = foo.emioi2c0;
    vi2c[1] = foo.emioi2c1;
    vtopm_axi_gp[0] <- mkAxi3MasterGather(foo.maxigp0, clocked_by axi_clock, reset_by axi_reset);
    vtopm_axi_gp[1] <- mkAxi3MasterGather(foo.maxigp1, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_gp[0] <- mkAxi3SlaveGather(foo.saxigp0, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_gp[1] <- mkAxi3SlaveGather(foo.saxigp1, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_acp[0] <- mkAxi3SlaveGather(foo.saxiacp, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[0] <- mkAxi3SlaveGather(foo.saxihp0, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[1] <- mkAxi3SlaveGather(foo.saxihp1, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[2] <- mkAxi3SlaveGather(foo.saxihp2, clocked_by axi_clock, reset_by axi_reset);
    vtops_axi_hp[3] <- mkAxi3SlaveGather(foo.saxihp3, clocked_by axi_clock, reset_by axi_reset);
    Wire#(Bit#(1)) fpgaidlenw <- mkDWire(1);
    rule fpgaidle;
       foo.fpgaidlen(fpgaidlenw);
    endrule
    rule misc;
       foo.emiosramintin(0);
       // UG585 "fclkclktrign is currently not supported and must be tied to ground"
       foo.fclkclktrign(0);
    endrule

`ifdef PS7EXTENDED
    interface Pps7Can can = vcan;
    interface Pps7Dma     dma = vdma;
    interface Pps7Enet     enet = venet;
    interface Pps7Sdio    sdio = vsdio;
    interface Pps7Spi    spi = vspi;
    interface Pps7Ttc    ttc = vttc;
    interface Pps7Uart    uart = vuart;
    interface Pps7Usb    usb = vusb;
    interface Pps7Event     event_ = foo.event_;
//    interface Pps7Fpga     fpga = foo.fpga;
    interface Pps7Ftmd     ftmd = foo.ftmd;
    interface Pps7Ftmt     ftmt = foo.ftmt;
    interface Pps7Pjtag     pjtag = foo.emiopjtag;
//    interface Pps7Sram     sram = foo.sram;
    interface Pps7Emiotrace     trace = foo.emiotrace;
    interface Pps7Wdt     wdt = foo.emiowdt;
`endif
    interface i2c = vi2c;
    interface ddr = foo.ddr;
    interface fclkclk = foo.fclkclk;
    interface fclkresetn = foo.fclkresetn;
    method Action      fclkclktrign(Bit#(4) v);
        foo.fclkclktrign(v);
    endmethod
    method Action      fpgaidlen(Bit#(1) v);
       fpgaidlenw <= v;
    endmethod
    interface gpio = foo.emiogpio;
    interface irq = foo.irq;
    interface mio = foo.mio;
    interface ps = foo.ps;

    interface m_axi_gp = vtopm_axi_gp;
    interface s_axi_gp = vtops_axi_gp;
    interface s_axi_hp = vtops_axi_hp;
    interface s_axi_acp = vtops_axi_acp[0];
endmodule

interface ZynqPins;
    (* prefix="DDR_Addr" *) interface Inout#(Bit#(15))     a;
    (* prefix="DDR_BankAddr" *) interface Inout#(Bit#(3))     ba;
    (* prefix="DDR_CAS_n" *) interface Inout#(Bit#(1))     casb;
    (* prefix="DDR_CKE" *) interface Inout#(Bit#(1))     cke;
    (* prefix="DDR_CS_n" *) interface Inout#(Bit#(1))     csb;
    (* prefix="DDR_Clk_n" *) interface Inout#(Bit#(1))     ckn;
    (* prefix="DDR_Clk_p" *) interface Inout#(Bit#(1))     ck;
    (* prefix="DDR_DM" *) interface Inout#(Bit#(4))     dm;
    (* prefix="DDR_DQ" *) interface Inout#(Bit#(32))     dq;
    (* prefix="DDR_DQS_n" *) interface Inout#(Bit#(4))     dqsn;
    (* prefix="DDR_DQS_p" *) interface Inout#(Bit#(4))     dqs;
    (* prefix="DDR_DRSTB" *) interface Inout#(Bit#(1))     drstb;
    (* prefix="DDR_ODT" *) interface Inout#(Bit#(1))     odt;
    (* prefix="DDR_RAS_n" *) interface Inout#(Bit#(1))     rasb;
    (* prefix="FIXED_IO_ddr_vrn" *) interface Inout#(Bit#(1))     vrn;
    (* prefix="FIXED_IO_ddr_vrp" *) interface Inout#(Bit#(1))     vrp;
    (* prefix="DDR_WEB" *) interface Inout#(Bit#(1))     web;
    (* prefix="MIO" *)
    interface Inout#(Bit#(54))       mio;
    (* prefix="FIXED_IO_ps" *)
    interface Pps7Ps ps;
endinterface

interface PS7;
    (* prefix="" *)
    interface ZynqPins pins;
    interface Vector#(2, AxiMasterCommon#(32,32,12))     m_axi_gp;
    interface Vector#(2, AxiSlaveCommon#(32,32,6,Empty)) s_axi_gp;
    interface Vector#(4, AxiSlaveCommon#(32,64,6,HPType))   s_axi_hp;
    interface Vector#(1, AxiSlaveCommon#(32,64,3,ACPType))   s_axi_acp;
    method Action                             interrupt(Bit#(1) v);
    interface Vector#(4, Clock) fclkclk;
    interface Vector#(4, Reset) fclkreset;
    interface Vector#(2, Pps7Emioi2c)  i2c;
    interface Clock derivedClock;
    interface Reset derivedReset;
`ifdef PS7EXTENDED
    interface Pps7Emiosdio emiosdio1;
`endif
endinterface

module mkPS7(PS7);
   // B2C converts a bit to a clock, enabling us to break the apparent cycle
   Vector#(4, B2C) b2c <- replicateM(mkB2C());

   // need the bufg here to reduce clock skew
   module mkBufferedClock#(Integer i)(Clock); let c <- mkClockBUFG(clocked_by b2c[i].c); return c; endmodule
   module mkBufferedReset#(Integer i)(Reset); let r <- mkResetBUFG(clocked_by b2c[i].c, reset_by b2c[i].r); return r; endmodule
   Vector#(4, Clock) fclk <- genWithM(mkBufferedClock);
   Vector#(4, Reset) freset <- genWithM(mkBufferedReset);

   Clock single_clock = fclk[0];
`ifdef ZYNQ_NO_RESET
   freset[0]          = noReset;
`endif
   let single_reset   = freset[0];

   ClockGenerator7Params clockParams = defaultValue;
   // input clock 200MHz for speed grade -2, 100MHz for speed grade -1
   // fpll needs to be in the range 600MHz - 1200MHz for either input clock
   //
   // fclkin = 1e9 / mainClockPeriod
   // fpll = 1e9 = mult_f * 1e9 / mainClockPeriod
   // mult_f = mainClockPeriod
   //
   // fclkout0 = 1e9 / divide_f = 1e9 / derivedClockPeriod
   // divide_f = derivedClockPeriod
   //
   clockParams.clkfbout_mult_f       = mainClockPeriod;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkin1_period      = mainClockPeriod;
   clockParams.clkout0_divide_f   = derivedClockPeriod;
   clockParams.clkout0_duty_cycle = 0.5;
   clockParams.clkout0_phase      = 0.0000;
   clockParams.clkout0_buffer     = True;
   clockParams.clkin_buffer = False;
   ClockGenerator7   clockGen <- mkClockGenerator7(clockParams, clocked_by single_clock, reset_by single_reset);
   let derived_clock = clockGen.clkout0;
   let derived_reset_unbuffered <- mkAsyncReset(2, single_reset, derived_clock);
   let derived_reset <- mkResetBUFG(clocked_by derived_clock, reset_by derived_reset_unbuffered);

   PS7LIB ps7 <- mkPS7LIB(single_clock, single_reset, clocked_by single_clock, reset_by single_reset);

   // this rule connects the fclkclk wires to the clock net via B2C
   for (Integer i = 0; i < 4; i = i + 1) begin
      ReadOnly#(Bit#(4)) fclkb;
      ReadOnly#(Bit#(4)) fclkresetnb;
      fclkb       <- mkNullCrossingWire(b2c[i].c, ps7.fclkclk);
      fclkresetnb <- mkNullCrossingWire(b2c[i].c, ps7.fclkresetn);
      rule b2c_rule1;
	 b2c[i].inputclock(fclkb[i]);
	 b2c[i].inputreset(fclkresetnb[i]);
      endrule
      rule issue_rule;
         ps7.s_axi_hp[i].extra.rdissuecap1en(0);
         ps7.s_axi_hp[i].extra.wrissuecap1en(0);
      endrule
   end

   IDELAYCTRL idel <- mkIDELAYCTRL(2, clocked_by fclk[3], reset_by freset[0]);

    rule arb_rule;
        ps7.ddr.arb(4'b0);
    endrule

`ifdef PS7EXTENDED
    interface Pps7Emiosdio emiosdio1 = ps7.sdio[1];
`endif
    interface ZynqPins pins;
    interface a = ps7.ddr.a;
    interface ba = ps7.ddr.ba;
    interface casb = ps7.ddr.casb;
    interface cke = ps7.ddr.cke;
    interface csb = ps7.ddr.csb;
    interface ckn = ps7.ddr.ckn;
    interface ck = ps7.ddr.ckp;
    interface dm = ps7.ddr.dm;
    interface dq = ps7.ddr.dq;
    interface dqsn = ps7.ddr.dqsn;
    interface dqs = ps7.ddr.dqsp;
    interface drstb = ps7.ddr.drstb;
    interface odt = ps7.ddr.odt;
    interface rasb = ps7.ddr.rasb;
    interface vrn = ps7.ddr.vrn;
    interface vrp = ps7.ddr.vrp;
    interface web = ps7.ddr.web;
    interface mio = ps7.mio;
    interface ps = ps7.ps;
    endinterface
    interface m_axi_gp = ps7.m_axi_gp;
    interface s_axi_gp = ps7.s_axi_gp;
    interface s_axi_hp = ps7.s_axi_hp;
    interface fclkclk = fclk;
    interface fclkreset = freset;
    interface derivedClock = derived_clock;
    interface derivedReset = derived_reset;
    method Action interrupt(Bit#(1) v);
        ps7.irq.f2p({19'b0, v});
    endmethod
    interface i2c = ps7.i2c;
   interface s_axi_acp = cons(ps7.s_axi_acp, nil);
endmodule

`ifdef USE_ACP
typedef 1 NumAcp;
`else
typedef 0 NumAcp;
`endif

instance ConnectableWithTrace#(PS7, ConnectalTop#(32,64,ipins,nMasters), BscanTop);
   module mkConnectionWithTrace#(PS7 ps7, ConnectalTop#(32,64,ipins,nMasters) top, BscanTop bscan)(Empty);

      Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(top.slave);
      mkConnectionWithTrace(ps7.m_axi_gp[0].client, ctrl, bscan);

`ifdef USE_ACP
      begin
	 Axi3Master#(32,64,3) acp_m_axi <- mkAxiDmaMaster(top.masters[0]);
	 mkConnection(acp_m_axi, ps7.s_axi_acp[0].server);
      end
      rule acp_aruser;
	 ps7.s_axi_acp[0].extra.aruser(5'h1f);
      endrule
      rule acp_awuser;
	 ps7.s_axi_acp[0].extra.awuser(5'h1f);
      endrule
`endif
      module mkAxiMasterConnection#(Integer i)(Axi3Master#(32,64,6));
	 let m_axi <- mkAxiDmaMaster(top.masters[i+valueOf(NumAcp)]);
	 mkConnection(m_axi, ps7.s_axi_hp[i].server);
	 return m_axi;
      endmodule
      Vector#(TSub#(nMasters,NumAcp), Axi3Master#(32,64,6)) m_axis <- genWithM(mkAxiMasterConnection);

   endmodule
endinstance


fixed error introduced in timing closure improvement

// Copyright (c) 2016 P4FPGA Project

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

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

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

// Deparser Template
import Library::*;
import BRAMFIFO::*;
`include "Debug.defines"

// app-specific structs
`define DEPARSER_STRUCT
`include "DeparserGenerated.bsv"
`undef DEPARSER_STRUCT

`define COLLECT_RULE(collectrule, rl) collectrule = List::cons (rl, collectrule)

typeclass CheckForward#(type t);
   function Bool checkForward(t x);
endtypeclass
instance CheckForward#(Maybe#(Header#(t)));
   function Bool checkForward(Maybe#(Header#(t)) x);
      case (x) matches
         tagged Valid .h: begin
            return h.state matches tagged Forward ? True : False;
         end
         tagged Invalid: begin
            return False;
         end
      endcase
   endfunction
endinstance

typeclass UpdateState#(type t);
   function t updateState(t x, HeaderState state);
endtypeclass
instance UpdateState#(Maybe#(Header#(t)));
   function Maybe#(Header#(t)) updateState(Maybe#(Header#(t)) x, HeaderState state);
      case (x) matches
         tagged Valid .h: begin
            return tagged Valid Header {hdr: h.hdr, state: state};
         end
         tagged Invalid: begin
            return tagged Invalid;
         end
      endcase
   endfunction
endinstance

typedef TDiv#(PktDataWidth, 8) MaskWidth;
typedef TLog#(PktDataWidth) DataSize;
typedef TLog#(TDiv#(PktDataWidth, 8)) MaskSize;
typedef TAdd#(DataSize, 1) NumBits;
typedef TAdd#(MaskSize, 1) NumBytes;

interface Deparser;
   interface PipeIn#(MetadataT) metadata;
   interface PktWriteServer#(16) writeServer;
   interface PktWriteClient#(16) writeClient;
   method Action set_verbosity (int verbosity);
   method DeparserPerfRec read_perf_info ();
endinterface
(* synthesize *)
module mkDeparser (Deparser);
   `PRINT_DEBUG_MSG

   FIFOF#(ByteStream#(16)) data_in_ff <- mkFIFOF();
   FIFOF#(ByteStream#(16)) data_out_ff <- mkFIFOF();
   FIFOF#(MetadataT) meta_in_ff <- mkSizedFIFOF(16);
   FIFO#(DeparserState) deparse_state_ff <- mkPipelineFIFO();
   Array#(Reg#(Bit#(10))) rg_next_header_len <- mkCReg(3, 0);
   Array#(Reg#(Bit#(10))) rg_processed <- mkCReg(3, 0); // number of bytes in current header that have been sent.
   Array#(Reg#(Bit#(10))) rg_buffered <- mkCReg(3, 0); // number of bytes to shift to append new bytes to rg_tmp
   Array#(Reg#(Bit#(512))) rg_tmp <- mkCReg(2, 0);
   Array#(Reg#(Bool)) deparse_done <- mkCReg(2, True);
   Array#(Reg#(Bool)) header_done <- mkCReg(2, True);
   Array#(Reg#(MetadataT)) meta <- mkCReg(2, defaultValue);
   PulseWire w_deparse_header_done <- mkPulseWire();

   // pipeline register at data_in
   Array#(Reg#(ByteStream#(16))) data_in_tmp <- mkCReg(2, defaultValue);

   // stage 1
   FIFO#(void) flit_ff <- mkFIFO;
   Reg#(ByteStream#(16)) deparse_send_r <- mkReg(unpack(0));
   rule stage_1;
      let _ <- toGet(flit_ff).get;
      data_out_ff.enq(deparse_send_r);
   endrule

   function Action report_deparse_action(String msg, Bit#(10) buffered, Bit#(10) processed, Bit#(10) shift, Bit#(512) data);
    action
      if (cf_verbosity > 0) begin
        $display("(%0d) Deparser:report_deparse_action %s buffered %d %d %d data %h", $time, msg, buffered, processed, shift, data);
      end
    endaction
  endfunction
  function Action fetch_next_header(Bit#(10) len);
    action
      rg_next_header_len[0] <= len;
    endaction
  endfunction
  function Action move_buffered_amt(Bit#(10) len);
    action
      rg_buffered[0] <= rg_buffered[0] + len;
    endaction
  endfunction
  function Action succeed_and_next(Bit#(10) len);
    action
      rg_processed[0] <= rg_processed[0] + len;
    endaction
  endfunction
  function Bit#(max) create_mask(LUInt#(max) count);
    Bit#(max) v = (1 << count) - 1;
    return v;
  endfunction

  // app-specific states
  `define DEPARSER_STATE
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_STATE

  // key: we let rl_deparse_start preempts rl_deparse_payload
  (* preempts = "rl_deparse_start, rl_deparse_payload" *)
  rule rl_deparse_start if (deparse_done[1] && data_in_ff.first.sop);
    // get new metadata
    deparse_done[1] <= False;
    header_done[1] <= False;
    let metadata = meta_in_ff.first;
    meta_in_ff.deq;
    meta[1] <= metadata;
    transit_next_state(metadata);
    dbprint(4, $format("Deparser:rl_start_state start deparse %d", valueOf(SizeOf#(DeparserState))));
    dbprint(1, $format("START deparse pkt"));
  endrule

  // process payload portion of packet, until last beat
  rule rl_deparse_payload if (deparse_done[1] && !data_in_tmp[1].eop);
    let v = data_in_ff.first;
    data_in_ff.deq;
    data_in_tmp[1] <= v;
    if (rg_buffered[1] != 0) begin
      Bit#(128) data_mask = create_mask(cExtend(rg_buffered[1]));
      Bit#(16) mask_out = create_mask(cExtend(rg_buffered[1] >> 3));
      let data = ByteStream { sop: data_in_tmp[1].sop,
                              eop: data_in_tmp[1].eop,
                              data: truncate(rg_tmp[1]) & data_mask,
                              mask: mask_out,
                              user:data_in_tmp[1].user};
      deparse_send_r <= data;
      flit_ff.enq(?);
      dbprint(4, $format("Deparser:rl_deparse_payload rg_buffered=%d", rg_buffered[1], fshow(data)));
      rg_buffered[1] <= 0;
    end
    else begin
      dbprint(4, $format("Deparser:rl_deparse_payload ", fshow(v)));
      let data = ByteStream { sop: data_in_tmp[1].sop,
                              eop: data_in_tmp[1].eop,
                              data: data_in_tmp[1].data,
                              mask: data_in_tmp[1].mask,
                              user: data_in_tmp[1].user };
      deparse_send_r <= data;
      flit_ff.enq(?);
    end
  endrule

  // reset all temporary states at last beat
  rule rl_reset if (deparse_done[1] && data_in_tmp[1].eop);
    data_in_tmp[1] <= defaultValue;
    rg_tmp[1] <= 0;
    rg_buffered[2] <= 0;
    rg_processed[2] <= 0;
    dbprint(4, $format("Deparser:rl_reset"));
    let data = ByteStream { sop: data_in_tmp[1].sop,
                            eop: data_in_tmp[1].eop,
                            data: data_in_tmp[1].data,
                            mask: data_in_tmp[1].mask,
                            user: data_in_tmp[1].user };
    deparse_send_r <= data;
    flit_ff.enq(?);
  endrule

  // from deparse state, indicate header is all parsed
  rule rl_deparse_done if (w_deparse_header_done);
    // set counter: rg_next_header_len
    fetch_next_header(0);
    header_done[0] <= True;
    dbprint(4, $format("Deparser:rl_deparse_header_done"));
  endrule

  // wait till all processed bits are sent, cont. to send payload.
  // some data are buffered not processed.
  rule rl_wait_till_processed_done if (!deparse_done[1] && header_done[1] && (rg_processed[1] == 0));
    // wait till processed is done
    deparse_done[1] <= True;
    dbprint(3, $format("Deparser:rl_wait_till_processed_done"));
  endrule

  // apply mask and send data
  // use rg_processed to keep track how much data in buffer has been processed;
  // use rg_buffered to keep track how much more data is yet to be processed;
  rule rl_deparse_send if (!deparse_done[1] && (rg_processed[1] > 0));
    // rg_tmp >> amt
    // rg_processed -= amt
    // rg_buffered -= amt
    let amt = 128;
    if (rg_processed[1] < 128) begin
       amt = rg_processed[1];
    end
    Bit#(128) data_out = truncate(rg_tmp[1] & create_mask(cExtend(amt)));
    Bit#(16) mask_out = create_mask(cExtend(amt >> 3));
    let data = ByteStream { sop: data_in_tmp[1].sop,
                            eop: data_in_tmp[1].eop,
                            data: data_out,
                            mask: mask_out,
                            user: data_in_tmp[1].user };
    rg_tmp[1] <= rg_tmp[1] >> amt;
    rg_processed[1] <= rg_processed[1] - amt;
    rg_buffered[1] <= rg_buffered[1] - amt;
    deparse_send_r <= data;
    flit_ff.enq(?);
    dbprint(4, $format("Deparser:rl_deparse_send rg_processed=%d rg_buffered=%d amt=%d", rg_processed[1], rg_buffered[1], amt, fshow(data)));
  endrule

  function Rules genDeparseNextRule(PulseWire wl, DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_next if (wl);
        // update counter : rg_next_header_len
        deparse_state_ff.enq(state);
        fetch_next_header(len);
      endrule
    endrules);
  endfunction

  function Rules genDeparseLoadRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_load if ((deparse_state_ff.first == state) && (rg_buffered[0] < len));
        // take data from data_in_ff, shift and append
        // rg_tmp = data << rg_buffered | rg_tmp;
        // rg_buffered += len
        let v = data_in_ff.first;
        data_in_tmp[0] <= v;
        rg_tmp[0] <= zeroExtend(v.data) << rg_buffered[0] | rg_tmp[0];

        dbprint(4, $format("Deparser:rl_data_ff_load "));
        data_in_ff.deq;

        UInt#(NumBytes) n_bytes_used = countOnes(v.mask);
        UInt#(NumBits) n_bits_used = cExtend(n_bytes_used) << 3;
        move_buffered_amt(cExtend(n_bits_used));
        dbprint(4, $format("load state %d %d ", rg_buffered[0], n_bits_used, fshow(state)));
      endrule
    endrules);
  endfunction

  function Rules genDeparseSendRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_send if ((deparse_state_ff.first == state) && (rg_buffered[0] >= len));
        // rg_processed += len
        // r <= rg_processed ?
        // amt = rg_processed < 128 ? rg_processed : 128;
        // rg_processed -= amt
        // rg_buffered -= amt
        // rg_tmp >> amt
        succeed_and_next(len);
        deparse_state_ff.deq;
        let metadata = meta[0];
        metadata = update_metadata(state);
        transit_next_state(metadata);
        meta[0] <= metadata;
        dbprint(4, $format("RULE: deparse send %d %d", rg_buffered[0], rg_processed[0]));
      endrule
    endrules);
  endfunction

  List#(Rules) deparse_fsm = List::nil;

  `define DEPARSER_RULES
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_RULES

  Empty fsmrl <- addRules(foldl(rJoin, emptyRules, fsmRules));

  interface metadata = toPipeIn(meta_in_ff);
  interface PktWriteServer writeServer;
    interface writeData = toPut(data_in_ff);
  endinterface
  interface PktWriteClient writeClient;
    interface writeData = toGet(data_out_ff);
  endinterface
  method Action set_verbosity (int verbosity);
    cf_verbosity <= verbosity;
  endmethod
endmodule

// Copyright (c) 2016 P4FPGA Project

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

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

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

// Deparser Template
import Library::*;
import BRAMFIFO::*;
`include "Debug.defines"

// app-specific structs
`define DEPARSER_STRUCT
`include "DeparserGenerated.bsv"
`undef DEPARSER_STRUCT

`define COLLECT_RULE(collectrule, rl) collectrule = List::cons (rl, collectrule)

typeclass CheckForward#(type t);
   function Bool checkForward(t x);
endtypeclass
instance CheckForward#(Maybe#(Header#(t)));
   function Bool checkForward(Maybe#(Header#(t)) x);
      case (x) matches
         tagged Valid .h: begin
            return h.state matches tagged Forward ? True : False;
         end
         tagged Invalid: begin
            return False;
         end
      endcase
   endfunction
endinstance

typeclass UpdateState#(type t);
   function t updateState(t x, HeaderState state);
endtypeclass
instance UpdateState#(Maybe#(Header#(t)));
   function Maybe#(Header#(t)) updateState(Maybe#(Header#(t)) x, HeaderState state);
      case (x) matches
         tagged Valid .h: begin
            return tagged Valid Header {hdr: h.hdr, state: state};
         end
         tagged Invalid: begin
            return tagged Invalid;
         end
      endcase
   endfunction
endinstance

typedef TDiv#(PktDataWidth, 8) MaskWidth;
typedef TLog#(PktDataWidth) DataSize;
typedef TLog#(TDiv#(PktDataWidth, 8)) MaskSize;
typedef TAdd#(DataSize, 1) NumBits;
typedef TAdd#(MaskSize, 1) NumBytes;

interface Deparser;
   interface PipeIn#(MetadataT) metadata;
   interface PktWriteServer#(16) writeServer;
   interface PktWriteClient#(16) writeClient;
   method Action set_verbosity (int verbosity);
   method DeparserPerfRec read_perf_info ();
endinterface
(* synthesize *)
module mkDeparser (Deparser);
   `PRINT_DEBUG_MSG

   FIFOF#(ByteStream#(16)) data_in_ff <- mkFIFOF();
   FIFOF#(ByteStream#(16)) data_out_ff <- mkFIFOF();
   FIFOF#(MetadataT) meta_in_ff <- mkSizedFIFOF(16);
   FIFO#(DeparserState) deparse_state_ff <- mkPipelineFIFO();
   Array#(Reg#(Bit#(10))) rg_next_header_len <- mkCReg(3, 0);
   Array#(Reg#(Bit#(10))) rg_processed <- mkCReg(3, 0); // number of bytes in current header that have been sent.
   Array#(Reg#(Bit#(10))) rg_buffered <- mkCReg(3, 0); // number of bytes to shift to append new bytes to rg_tmp
   Array#(Reg#(Bit#(512))) rg_tmp <- mkCReg(2, 0);
   Array#(Reg#(Bool)) deparse_done <- mkCReg(2, True);
   Array#(Reg#(Bool)) header_done <- mkCReg(2, True);
   Array#(Reg#(MetadataT)) meta <- mkCReg(2, defaultValue);
   PulseWire w_deparse_header_done <- mkPulseWire();
   Array#(Reg#(Bool)) sop_tmp <- mkCReg(2, False);
   Array#(Reg#(Bool)) eop_tmp <- mkCReg(2, False);

   let mask_this_cycle = data_in_ff.first.mask;
   let sop_this_cycle = data_in_ff.first.sop;
   let eop_this_cycle = data_in_ff.first.eop;
   let data_this_cycle = data_in_ff.first.data;

   // stage 1
   FIFO#(void) flit_ff <- mkFIFO;
   Reg#(ByteStream#(16)) deparse_send_r <- mkReg(unpack(0));
   rule stage_1;
      let _ <- toGet(flit_ff).get;
      data_out_ff.enq(deparse_send_r);
   endrule

   function Action report_deparse_action(String msg, Bit#(10) buffered, Bit#(10) processed, Bit#(10) shift, Bit#(512) data);
    action
      if (cf_verbosity > 0) begin
        $display("(%0d) Deparser:report_deparse_action %s buffered %d %d %d data %h", $time, msg, buffered, processed, shift, data);
      end
    endaction
  endfunction
  function Action fetch_next_header(Bit#(10) len);
    action
      rg_next_header_len[0] <= len;
    endaction
  endfunction
  function Action move_buffered_amt(Bit#(10) len);
    action
      rg_buffered[0] <= rg_buffered[0] + len;
    endaction
  endfunction
  function Action succeed_and_next(Bit#(10) len);
    action
      rg_processed[0] <= rg_processed[0] + len;
    endaction
  endfunction
  function Bit#(max) create_mask(LUInt#(max) count);
    Bit#(max) v = (1 << count) - 1;
    return v;
  endfunction

  // app-specific states
  `define DEPARSER_STATE
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_STATE

  // key: we let rl_deparse_start preempts rl_deparse_payload
  (* preempts = "rl_deparse_start, rl_deparse_payload" *)
  rule rl_deparse_start if (deparse_done[1] && sop_this_cycle);
    // get new metadata
    deparse_done[1] <= False;
    header_done[1] <= False;
    let metadata = meta_in_ff.first;
    meta_in_ff.deq;
    meta[1] <= metadata;
    transit_next_state(metadata);
    dbprint(4, $format("Deparser:rl_start_state start deparse %d", valueOf(SizeOf#(DeparserState))));
    dbprint(1, $format("START deparse pkt"));
  endrule

  // process payload portion of packet, until last beat
  rule rl_deparse_payload if (deparse_done[1] && !eop_this_cycle);
    let v = data_in_ff.first;
    data_in_ff.deq;
    if (rg_buffered[1] != 0) begin
      Bit#(128) data_mask = create_mask(cExtend(rg_buffered[1]));
      Bit#(16) mask_out = create_mask(cExtend(rg_buffered[1] >> 3));
      let data = ByteStream { sop: v.sop, eop: v.eop, data: truncate(rg_tmp[1]) & data_mask, mask: mask_out, user:0 };
      deparse_send_r <= data;
      flit_ff.enq(?);
      dbprint(4, $format("Deparser:rl_deparse_payload rg_buffered=%d", rg_buffered[1], fshow(data)));
      rg_buffered[1] <= 0;
    end
    else begin
      dbprint(4, $format("Deparser:rl_deparse_payload ", fshow(v)));
      deparse_send_r <= v;
      flit_ff.enq(?);
    end
  endrule

  // reset all temporary states at last beat
  rule rl_reset if (deparse_done[1] && eop_this_cycle);
    // forward data_in to data_out
    let v = data_in_ff.first;
    data_in_ff.deq;
    rg_tmp[1] <= 0;
    rg_buffered[2] <= 0;
    rg_processed[2] <= 0;
    dbprint(4, $format("Deparser:rl_reset"));
    deparse_send_r <= v;
    flit_ff.enq(?);
  endrule

  // from deparse state, indicate header is all parsed
  rule rl_deparse_done if (w_deparse_header_done);
    // set counter: rg_next_header_len
    fetch_next_header(0);
    header_done[0] <= True;
    dbprint(4, $format("Deparser:rl_deparse_header_done"));
  endrule

  // wait till all processed bits are sent, cont. to send payload.
  // some data are buffered not processed.
  rule rl_wait_till_processed_done if (!deparse_done[1] && header_done[1] && (rg_processed[1] == 0));
    // wait till processed is done
    deparse_done[1] <= True;
    dbprint(3, $format("Deparser:rl_wait_till_processed_done"));
  endrule

  // apply mask and send data
  // use rg_processed to keep track how much data in buffer has been processed;
  // use rg_buffered to keep track how much more data is yet to be processed;
  rule rl_deparse_send if (!deparse_done[1] && (rg_processed[1] > 0));
    // rg_tmp >> amt
    // rg_processed -= amt
    // rg_buffered -= amt
    let amt = 128;
    if (rg_processed[1] < 128) begin
       amt = rg_processed[1];
    end
    Bit#(128) data_out = truncate(rg_tmp[1] & create_mask(cExtend(amt)));
    Bit#(16) mask_out = create_mask(cExtend(amt >> 3));
    let data = ByteStream { sop: sop_tmp[1], eop: eop_tmp[1], data: data_out, mask: mask_out, user:0 };
    rg_tmp[1] <= rg_tmp[1] >> amt;
    rg_processed[1] <= rg_processed[1] - amt;
    rg_buffered[1] <= rg_buffered[1] - amt;
    deparse_send_r <= data;
    flit_ff.enq(?);
    dbprint(4, $format("Deparser:rl_deparse_send rg_processed=%d rg_buffered=%d amt=%d", rg_processed[1], rg_buffered[1], amt, fshow(data)));
  endrule

  function Rules genDeparseNextRule(PulseWire wl, DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_next if (wl);
        // update counter : rg_next_header_len
        deparse_state_ff.enq(state);
        fetch_next_header(len);
      endrule
    endrules);
  endfunction

  function Rules genDeparseLoadRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_load if ((deparse_state_ff.first == state) && (rg_buffered[0] < len));
        // take data from data_in_ff, shift and append
        // rg_tmp = data << rg_buffered | rg_tmp;
        // rg_buffered += len
        rg_tmp[0] <= zeroExtend(data_this_cycle) << rg_buffered[0] | rg_tmp[0];
        sop_tmp[0] <= sop_this_cycle;
        eop_tmp[0] <= eop_this_cycle;

        dbprint(4, $format("Deparser:rl_data_ff_load "));
        data_in_ff.deq;

        UInt#(NumBytes) n_bytes_used = countOnes(mask_this_cycle);
        UInt#(NumBits) n_bits_used = cExtend(n_bytes_used) << 3;
        move_buffered_amt(cExtend(n_bits_used));
        dbprint(4, $format("load state %d %d ", rg_buffered[0], n_bits_used, fshow(state)));
      endrule
    endrules);
  endfunction

  function Rules genDeparseSendRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_send if ((deparse_state_ff.first == state) && (rg_buffered[0] >= len));
        // rg_processed += len
        // r <= rg_processed ?
        // amt = rg_processed < 128 ? rg_processed : 128;
        // rg_processed -= amt
        // rg_buffered -= amt
        // rg_tmp >> amt
        succeed_and_next(len);
        deparse_state_ff.deq;
        let metadata = meta[0];
        metadata = update_metadata(state);
        transit_next_state(metadata);
        meta[0] <= metadata;
        dbprint(4, $format("RULE: deparse send %d %d", rg_buffered[0], rg_processed[0]));
      endrule
    endrules);
  endfunction

  List#(Rules) deparse_fsm = List::nil;

  `define DEPARSER_RULES
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_RULES

  Empty fsmrl <- addRules(foldl(rJoin, emptyRules, fsmRules));

  interface metadata = toPipeIn(meta_in_ff);
  interface PktWriteServer writeServer;
    interface writeData = toPut(data_in_ff);
  endinterface
  interface PktWriteClient writeClient;
    interface writeData = toGet(data_out_ff);
  endinterface
  method Action set_verbosity (int verbosity);
    cf_verbosity <= verbosity;
  endmethod
endmodule


added edge detection Related git tag:     imageon 6b4cea1866a2b40a335a6b0746c698ad8375ca87

// 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 Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
    method Action           align_start(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(3)          samplein();
    method Action           autoalign(Bit#(1) v);
    method Action           training(Bit#(10) v);
    method Action           manual_tap(Bit#(10) v);
    method Action           reset(Bit#(1) v);
    method Action           dataout(Bit#(10) v);
    method Action           edgeint(Bit#(10) v);
    method Action           edgeintor(Bit#(1) v);
    method Bit#(1)          ctrl_bitslip();
    method Bit#(1)          ctrl_fifo_reset();
    method Bit#(3)          ctrl_reset_inc_ce();
    method Action           endhandshake(Bit#(1) v);
    method Bit#(1)          starthandshake();
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Reset clkdiv_reset)(Iserdesbvi);
    input_clock clkdiv () = clkdiv;
    default_clock clock(CLOCK);
    input_reset clkdiv_reset() clocked_by(clkdiv) = clkdiv_reset;
    method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
    method ALIGN_BUSY       align_busy() clocked_by (clock);
    method ALIGNED          aligned() clocked_by (clock);
    method CTRL_SAMPLEIN    samplein() clocked_by (clock);
    method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
    method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
    method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
    method                  reset(RESET) enable((*inhigh*) en17) clocked_by (clkdiv) reset_by(clkdiv_reset);
    method                  dataout(CTRL_DATA) enable((*inhigh*) en18) clocked_by(clock);
    method                  edgeint(EDGE_INT) enable((*inhigh*) en19) clocked_by(clock);
    method                  edgeintor(EDGE_INT_OR) enable((*inhigh*) en21) clocked_by(clock);
    method CTRL_BITSLIP     ctrl_bitslip() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_FIFO_RESET   ctrl_fifo_reset() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_RESET_INC_CE ctrl_reset_inc_ce() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method                  endhandshake(end_handshake) enable((*inhigh*) en20) clocked_by(clock);
    method start_handshake starthandshake();
    schedule (edgeintor, edgeint, endhandshake, starthandshake, ctrl_reset_inc_ce, ctrl_bitslip, ctrl_fifo_reset, reset, dataout, align_busy, aligned, samplein, align_start, autoalign, training, manual_tap)
         CF (edgeintor, edgeint, endhandshake, starthandshake, ctrl_reset_inc_ce, ctrl_bitslip, ctrl_fifo_reset, reset, dataout, align_busy, aligned, samplein, align_start, autoalign, training, manual_tap);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
    method Action           ibufdso(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(1)          sampleinfirstbit();
    method Bit#(1)          sampleinlastbit();
    method Bit#(1)          sampleinotherbit();
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          empty();
    method Bit#(10)         dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action            di(Bit#(16) v);
   method Action            rden(Bit#(1) v);
   method Action            wren(Bit#(1) v);
   method Action            reset(Bit#(1) v);
   method Bit#(16)          dataout();
   method Bit#(1)           empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    no_reset;
    port DIP = 0;

    method          reset(RST) enable((*inhigh*) en9) clocked_by (clkdiv);
    method          di(DI) enable((*inhigh*) en0) clocked_by (clock); //clkdiv);
    method          rden(RDEN) enable((*inhigh*) en2) clocked_by (clock);
    method          wren(WREN) enable((*inhigh*) en3) clocked_by (clock);
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
    schedule (reset, di, rden, wren, dataout, empty) CF (reset, di, rden, wren, dataout, empty);
endmodule: mkFIFO18

typedef enum { DIdle, DValid, DLow} DState deriving (Bits,Eq);
typedef enum { HIdle, HHigh, HLow} HState deriving (Bits,Eq);

module mkIserdesDatadeser#(Clock serdes_clock, Reset serdes_reset, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock, serdes_reset);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    IdelayE2 delaye2 <- mkIDELAYE2(IDELAYE2_Config {
        cinvctrl_sel: "FALSE", delay_src: "IDATAIN",
        high_performance_mode: "TRUE",
        idelay_type: "VARIABLE", idelay_value: 0,
        pipe_sel: "FALSE", refclk_frequency: 200, signal_pattern: "DATA"},
        defaultClock, clocked_by serdes_clock);
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    IserdesE2 master_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "MASTER", iobdelay: "IFD"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    IserdesE2 slave_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "SLAVE", iobdelay: "NONE"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    Wire#(Bit#(1)) bvi_delay_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_reset_reg <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    SyncBitIfc#(Bit#(1)) bvi_resets_reg <- mkSyncBitToCC(serdes_clock, serdes_reset);
    Wire#(Bit#(1)) bvi_fifo_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) dcounter <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(DState)  dstate <- mkReg(DIdle, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe0 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe1 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_reset <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_reset_r <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_wren_r <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) sync_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) sync_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    ReadOnly#(Bit#(3)) samplein_null <- mkNullCrossingWire(serdes_clock, serbvi.samplein());

    SyncBitIfc#(Bit#(1)) fifo_wren_sync <- mkSyncBitToCC(serdes_clock, serdes_reset);
    Vector#(10, SyncBitIfc#(Bit#(1))) iserdes_data <-  replicateM(mkSyncBitToCC(serdes_clock, serdes_reset));
    SyncBitIfc#(Bit#(1)) dackint <- mkSyncBitToCC(serdes_clock, serdes_reset);
    Reg#(Bit#(1)) dackint_last <- mkReg(0);

    Reg#(Bit#(1)) iserdes_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) iodelay_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(10)) ctrl_data <- mkReg(0);
    Reg#(HState)  hstate <- mkReg(HIdle);
    Reg#(Bit#(6)) hcounter <- mkReg(0);
    Reg#(Bit#(1)) edge_intor_reg <- mkReg(0);
    SyncBitIfc#(Bit#(1)) item_req_wire <- mkSyncBit(defaultClock, defaultReset, serdes_clock);

    rule reset_clock_rule;
        bvi_resets_reg.send(bvi_reset_reg);
    endrule

    rule wrensyncr_rule if (bvi_reset_reg == 0);
        dfifo_wren_r <= 0;
        fifo_wren_sync.send(0);
        iserdes_bitslip <= 0;
        iodelay_reset_inc_ce <= 0;
        dstate <= DIdle;
        dackint.send(0);
    endrule
    rule wrensync_rule if (bvi_reset_reg != 0);
        let fwsync = 0;
        dfifo_wren_r <= bvi_fifo_wren_wire;
        if (bvi_delay_wren_wire == 1 && samplein_null[2] == 1)
            fwsync = dfifo_wren_r;
        else
            fwsync = bvi_fifo_wren_wire;
        fifo_wren_sync.send(fwsync);
        iodelay_reset_inc_ce <= sync_reset_inc_ce;
    endrule

    rule clkdiv_rule if (bvi_reset_reg != 0);
        let ds = dstate;
        let dc = dcounter;
        let sric = sync_reset_inc_ce;
        let sbs = 0;

        dc = dc - 1;
        dreqpipe0 <= item_req_wire.read();
        dreqpipe1 <= dreqpipe0;
        dfifo_reset_r <= serbvi.ctrl_fifo_reset();
        fifo_reset <= dfifo_reset_r;
        sric[0] = 0;
        sric[1] = 0;
        iserdes_bitslip <= sync_bitslip;
        if (dstate == DIdle && dreqpipe1 == 1)
            begin
            sric = serbvi.ctrl_reset_inc_ce();
            sbs = serbvi.ctrl_bitslip();
            dc = 3;
            ds = DValid;
            end
        if (dstate == DValid && dcounter[2] == 1)
            begin
            ds = DLow;
            end
        if (dstate == DLow && dreqpipe1 == 0)
            begin
            ds = DIdle;
            end
        dstate <= ds;
        dcounter <= dc;
        sync_reset_inc_ce <= sric;
        sync_bitslip <= sbs;
    endrule
    rule state1_rule if (bvi_reset_reg != 0 && dstate == DValid && dcounter[2] == 1);
        dackint.send(1);
    endrule
    rule state2_rule if (bvi_reset_reg != 0 && dstate == DLow && dreqpipe1 == 0);
        dackint.send(0);
    endrule

    rule setrule;
        dfifo.reset(iodelay_reset_inc_ce[2]);
        delaye2.reset(iodelay_reset_inc_ce[2]);
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(iodelay_reset_inc_ce[1] == 1);
        delaye2.ce(iodelay_reset_inc_ce[0]);
    endrule

    rule serdesdata_rule;
        master_data.d(0);
        master_data.bitslip(iserdes_bitslip);
        master_data.ce1(1);
        master_data.ce2(1);
        master_data.ddly(delaye2.dataout());
        master_data.ofb(0);
        master_data.dynclkdivsel(0);
        master_data.dynclksel(0);
        master_data.shiftin1(0);
        master_data.shiftin2(0);
        master_data.oclk(0);
        master_data.oclkb(0);
        master_data.reset(iodelay_reset_inc_ce[2]);
        slave_data.d(0);
        slave_data.bitslip(iserdes_bitslip);
        slave_data.ce1(1);
        slave_data.ce2(1);
        slave_data.ddly(0);
        slave_data.ofb(0);
        slave_data.dynclkdivsel(0);
        slave_data.dynclksel(0);
        slave_data.shiftin1(master_data.shiftout1());
        slave_data.shiftin2(master_data.shiftout2());
        slave_data.oclk(0);
        slave_data.oclkb(0);
        slave_data.reset(iodelay_reset_inc_ce[2]);
        let dout = {slave_data.q4(), slave_data.q3(), master_data.q8(),
           master_data.q7(), master_data.q6(), master_data.q5(),
           master_data.q4(), master_data.q3(), master_data.q2(), master_data.q1()};
        for (Integer i = 0; i < 10; i = i + 1)
            iserdes_data[i].send(dout[i]);
    endrule

    rule dackint_rule;
        Bit#(10) dout = 0;
        Bit#(10) edgeo = 0;
        for (Integer i = 0; i < 10; i = i + 1)
            dout[i] = iserdes_data[i].read();
        dackint_last <= dackint.read();
        if (dackint.read() == 1 && dackint_last == 0)
            ctrl_data <= dout;
        serbvi.dataout(dout);
        for (Integer i = 0; i < 9; i = i + 1)
            edgeo[i] = dout[i] ^ dout[i+1];
        edgeo[9] = dout[0] ^ dout[9];
        serbvi.edgeint(edgeo);
        edge_intor_reg <= pack(serbvi.starthandshake() == 0 && edgeo != 0);
        serbvi.edgeintor(edge_intor_reg);
        dfifo.di({6'b0,dout});
        dfifo.wren(fifo_wren_sync.read());
    endrule

    rule handinit_rule if (bvi_resets_reg.read() == 0);
        hstate <= HIdle;
        hcounter <= 0;
        item_req_wire.send(0);
        serbvi.endhandshake(0);
    endrule

    rule hand_rule if (bvi_resets_reg.read() != 0);
        let hs = hstate;
        let hend = 0;
        let hc = hcounter;
        hc = hc + 1;
        if (hstate == HIdle && serbvi.starthandshake() == 1)
            begin
            hc = 0;
            hs = HHigh;
            end
        if (hstate == HHigh && dackint.read() == 1)
            begin
            hc = 0;
            hs = HLow;
            end
        if (hstate == HHigh && hcounter >= 'h20)
            begin
            hend = 1;
            hs = HIdle;
            end
        if (hstate == HLow && (dackint.read() == 0 || hcounter >= 'h20))
            begin
            hend = 1;
            hs = HIdle;
            end
        serbvi.endhandshake(hend);
        hstate <= hs;
        hcounter <= hc;
    endrule
    rule hstate1_rule if (bvi_resets_reg.read() != 0 && hstate == HIdle && serbvi.starthandshake() == 1);
        item_req_wire.send(1);
    endrule
    rule hstate2_rule if (bvi_resets_reg.read() != 0 && hstate == HHigh && dackint.read() == 1);
        item_req_wire.send(0);
    endrule

    rule serdesrule;
        serbvi.align_start(align_start);
        serbvi.autoalign(autoalign);
        serbvi.training(training);
        serbvi.manual_tap(manual_tap);
        dfifo.rden(rden);
    endrule

    method Action ibufdso(Bit#(1) v);
        delaye2.idatain(v);
    endmethod
    method Bit#(1)                align_busy();
        return serbvi.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serbvi.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serbvi.samplein()[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serbvi.samplein()[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serbvi.samplein()[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        bvi_delay_wren_wire <= v;
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        bvi_fifo_wren_wire <= v;
    endmethod
    method Action                 reset(Bit#(1) v);
        bvi_reset_reg <= v;
        serbvi.reset(v);
    endmethod
    method Bit#(1)                empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdes_reset, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufdso(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule

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

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

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

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

import Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
    method Action           align_start(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(3)          samplein();
    method Action           autoalign(Bit#(1) v);
    method Action           training(Bit#(10) v);
    method Action           manual_tap(Bit#(10) v);
    method Action           reset(Bit#(1) v);
    method Action           dataout(Bit#(10) v);
    method Bit#(1)          ctrl_bitslip();
    method Bit#(1)          ctrl_fifo_reset();
    method Bit#(3)          ctrl_reset_inc_ce();
    method Action           endhandshake(Bit#(1) v);
    method Bit#(1)          starthandshake();
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Reset clkdiv_reset)(Iserdesbvi);
    input_clock clkdiv () = clkdiv;
    default_clock clock(CLOCK);
    input_reset clkdiv_reset() clocked_by(clkdiv) = clkdiv_reset;
    method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
    method ALIGN_BUSY       align_busy() clocked_by (clock);
    method ALIGNED          aligned() clocked_by (clock);
    method CTRL_SAMPLEIN    samplein() clocked_by (clock);
    method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
    method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
    method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
    method                  reset(RESET) enable((*inhigh*) en17) clocked_by (clkdiv) reset_by(clkdiv_reset);
    method                  dataout(CTRL_DATA) enable((*inhigh*) en18) clocked_by(clock);
    method CTRL_BITSLIP     ctrl_bitslip() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_FIFO_RESET   ctrl_fifo_reset() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_RESET_INC_CE ctrl_reset_inc_ce() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method                  endhandshake(end_handshake) enable((*inhigh*) en20) clocked_by(clock);
    method start_handshake_o starthandshake();
    schedule (endhandshake, starthandshake, ctrl_reset_inc_ce, ctrl_bitslip, ctrl_fifo_reset, reset, dataout, align_busy, aligned, samplein, align_start, autoalign, training, manual_tap)
         CF (endhandshake, starthandshake, ctrl_reset_inc_ce, ctrl_bitslip, ctrl_fifo_reset, reset, dataout, align_busy, aligned, samplein, align_start, autoalign, training, manual_tap);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
    method Action           ibufdso(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(1)          sampleinfirstbit();
    method Bit#(1)          sampleinlastbit();
    method Bit#(1)          sampleinotherbit();
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          empty();
    method Bit#(10)         dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action            di(Bit#(16) v);
   method Action            rden(Bit#(1) v);
   method Action            wren(Bit#(1) v);
   method Action            reset(Bit#(1) v);
   method Bit#(16)          dataout();
   method Bit#(1)           empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    no_reset;
    port DIP = 0;

    method          reset(RST) enable((*inhigh*) en9) clocked_by (clkdiv);
    method          di(DI) enable((*inhigh*) en0) clocked_by (clock); //clkdiv);
    method          rden(RDEN) enable((*inhigh*) en2) clocked_by (clock);
    method          wren(WREN) enable((*inhigh*) en3) clocked_by (clock);
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
    schedule (reset, di, rden, wren, dataout, empty) CF (reset, di, rden, wren, dataout, empty);
endmodule: mkFIFO18

typedef enum { DIdle, DValid, DLow} DState deriving (Bits,Eq);
typedef enum { HIdle, HHigh, HLow} HState deriving (Bits,Eq);

module mkIserdesDatadeser#(Clock serdes_clock, Reset serdes_reset, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock, serdes_reset);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    IdelayE2 delaye2 <- mkIDELAYE2(IDELAYE2_Config {
        cinvctrl_sel: "FALSE", delay_src: "IDATAIN",
        high_performance_mode: "TRUE",
        idelay_type: "VARIABLE", idelay_value: 0,
        pipe_sel: "FALSE", refclk_frequency: 200, signal_pattern: "DATA"},
        defaultClock, clocked_by serdes_clock);
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    IserdesE2 master_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "MASTER", iobdelay: "IFD"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    IserdesE2 slave_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "SLAVE", iobdelay: "NONE"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    Wire#(Bit#(1)) bvi_delay_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_reset_reg <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    SyncBitIfc#(Bit#(1)) bvi_resets_reg <- mkSyncBitToCC(serdes_clock, serdes_reset);
    Wire#(Bit#(1)) bvi_fifo_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) dcounter <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(DState)  dstate <- mkReg(DIdle, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe0 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe1 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_reset <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_reset_r <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_wren_r <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) sync_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) sync_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    ReadOnly#(Bit#(3)) samplein_null <- mkNullCrossingWire(serdes_clock, serbvi.samplein());

    SyncBitIfc#(Bit#(1)) fifo_wren_sync <- mkSyncBitToCC(serdes_clock, serdes_reset);
    Vector#(10, SyncBitIfc#(Bit#(1))) iserdes_data <-  replicateM(mkSyncBitToCC(serdes_clock, serdes_reset));
    SyncBitIfc#(Bit#(1)) dackint <- mkSyncBitToCC(serdes_clock, serdes_reset);
    Reg#(Bit#(1)) dackint_last <- mkReg(0);

    Reg#(Bit#(1)) iserdes_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) iodelay_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(10)) ctrl_data <- mkReg(0);
    Reg#(HState)  hstate <- mkReg(HIdle);
    Reg#(Bit#(6)) hcounter <- mkReg(0);
    SyncBitIfc#(Bit#(1)) item_req_wire <- mkSyncBit(defaultClock, defaultReset, serdes_clock);

    rule reset_clock_rule;
        bvi_resets_reg.send(bvi_reset_reg);
    endrule

    rule wrensyncr_rule if (bvi_reset_reg == 0);
        dfifo_wren_r <= 0;
        fifo_wren_sync.send(0);
        iserdes_bitslip <= 0;
        iodelay_reset_inc_ce <= 0;
        dstate <= DIdle;
        dackint.send(0);
    endrule
    rule wrensync_rule if (bvi_reset_reg != 0);
        let fwsync = 0;
        dfifo_wren_r <= bvi_fifo_wren_wire;
        if (bvi_delay_wren_wire == 1 && samplein_null[2] == 1)
            fwsync = dfifo_wren_r;
        else
            fwsync = bvi_fifo_wren_wire;
        fifo_wren_sync.send(fwsync);
        iodelay_reset_inc_ce <= sync_reset_inc_ce;
    endrule

    rule clkdiv_rule if (bvi_reset_reg != 0);
        let ds = dstate;
        let dc = dcounter;
        let sric = sync_reset_inc_ce;
        let sbs = 0;

        dc = dc - 1;
        dreqpipe0 <= item_req_wire.read();
        dreqpipe1 <= dreqpipe0;
        dfifo_reset_r <= serbvi.ctrl_fifo_reset();
        fifo_reset <= dfifo_reset_r;
        sric[0] = 0;
        sric[1] = 0;
        iserdes_bitslip <= sync_bitslip;
        if (dstate == DIdle && dreqpipe1 == 1)
            begin
            sric = serbvi.ctrl_reset_inc_ce();
            sbs = serbvi.ctrl_bitslip();
            dc = 3;
            ds = DValid;
            end
        if (dstate == DValid && dcounter[2] == 1)
            begin
            ds = DLow;
            end
        if (dstate == DLow && dreqpipe1 == 0)
            begin
            ds = DIdle;
            end
        dstate <= ds;
        dcounter <= dc;
        sync_reset_inc_ce <= sric;
        sync_bitslip <= sbs;
    endrule
    rule state1_rule if (bvi_reset_reg != 0 && dstate == DValid && dcounter[2] == 1);
        dackint.send(1);
    endrule
    rule state2_rule if (bvi_reset_reg != 0 && dstate == DLow && dreqpipe1 == 0);
        dackint.send(0);
    endrule

    rule setrule;
        dfifo.reset(iodelay_reset_inc_ce[2]);
        delaye2.reset(iodelay_reset_inc_ce[2]);
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(iodelay_reset_inc_ce[1] == 1);
        delaye2.ce(iodelay_reset_inc_ce[0]);
    endrule

    rule serdesdata_rule;
        master_data.d(0);
        master_data.bitslip(iserdes_bitslip);
        master_data.ce1(1);
        master_data.ce2(1);
        master_data.ddly(delaye2.dataout());
        master_data.ofb(0);
        master_data.dynclkdivsel(0);
        master_data.dynclksel(0);
        master_data.shiftin1(0);
        master_data.shiftin2(0);
        master_data.oclk(0);
        master_data.oclkb(0);
        master_data.reset(iodelay_reset_inc_ce[2]);
        slave_data.d(0);
        slave_data.bitslip(iserdes_bitslip);
        slave_data.ce1(1);
        slave_data.ce2(1);
        slave_data.ddly(0);
        slave_data.ofb(0);
        slave_data.dynclkdivsel(0);
        slave_data.dynclksel(0);
        slave_data.shiftin1(master_data.shiftout1());
        slave_data.shiftin2(master_data.shiftout2());
        slave_data.oclk(0);
        slave_data.oclkb(0);
        slave_data.reset(iodelay_reset_inc_ce[2]);
        let dout = {slave_data.q4(), slave_data.q3(), master_data.q8(),
           master_data.q7(), master_data.q6(), master_data.q5(),
           master_data.q4(), master_data.q3(), master_data.q2(), master_data.q1()};
        for (Integer i = 0; i < 10; i = i + 1)
            iserdes_data[i].send(dout[i]);
    endrule

    rule dackint_rule;
        Bit#(10) dout = 0;
        for (Integer i = 0; i < 10; i = i + 1)
            dout[i] = iserdes_data[i].read();
        dackint_last <= dackint.read();
        if (dackint.read() == 1 && dackint_last == 0)
            ctrl_data <= dout;
        serbvi.dataout(dout);
        dfifo.di({6'b0,dout});
        dfifo.wren(fifo_wren_sync.read());
    endrule

    rule handinit_rule if (bvi_resets_reg.read() == 0);
        hstate <= HIdle;
        hcounter <= 0;
        item_req_wire.send(0);
        serbvi.endhandshake(0);
    endrule

    rule hand_rule if (bvi_resets_reg.read() != 0);
        let hs = hstate;
        let hend = 0;
        let hc = hcounter;
        hc = hc + 1;
        if (hstate == HIdle && serbvi.starthandshake() == 1)
            begin
            hc = 0;
            hs = HHigh;
            end
        if (hstate == HHigh && dackint.read() == 1)
            begin
            hc = 0;
            hs = HLow;
            end
        if (hstate == HHigh && hcounter >= 'h20)
            begin
            hend = 1;
            hs = HIdle;
            end
        if (hstate == HLow && (dackint.read() == 0 || hcounter >= 'h20))
            begin
            hend = 1;
            hs = HIdle;
            end
        serbvi.endhandshake(hend);
        hstate <= hs;
        hcounter <= hc;
    endrule
    rule hstate1_rule if (bvi_resets_reg.read() != 0 && hstate == HIdle && serbvi.starthandshake() == 1);
        item_req_wire.send(1);
    endrule
    rule hstate2_rule if (bvi_resets_reg.read() != 0 && hstate == HHigh && dackint.read() == 1);
        item_req_wire.send(0);
    endrule

    rule serdesrule;
        serbvi.align_start(align_start);
        serbvi.autoalign(autoalign);
        serbvi.training(training);
        serbvi.manual_tap(manual_tap);
        dfifo.rden(rden);
    endrule

    method Action ibufdso(Bit#(1) v);
        delaye2.idatain(v);
    endmethod
    method Bit#(1)                align_busy();
        return serbvi.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serbvi.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serbvi.samplein()[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serbvi.samplein()[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serbvi.samplein()[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        bvi_delay_wren_wire <= v;
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        bvi_fifo_wren_wire <= v;
    endmethod
    method Action                 reset(Bit#(1) v);
        bvi_reset_reg <= v;
        serbvi.reset(v);
    endmethod
    method Bit#(1)                empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdes_reset, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufdso(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule