fixed log write, log read and reset warnings

// Copyright (c) 2015 Cornell University.

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

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

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

import Clocks::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import GetPut::*;
import Probe::*;

typedef struct {
   Bit#(8) port_no;
   Bit#(64) data;
} BufData deriving (Bits, Eq);

interface DtpIfc;
   interface PipeIn#(Bit#(128)) timestamp; // streaming time counter from NetTop.
   interface Vector#(4, PipeOut#(Bit#(53))) fromHost;
   interface Vector#(4, PipeIn#(Bit#(53)))  toHost;
   interface Vector#(4, PipeIn#(Bit#(32)))  delay;
   interface Vector#(4, PipeIn#(Bit#(32)))  state;
   interface Vector#(4, PipeIn#(Bit#(64)))  jumpCount;
   interface Vector#(4, PipeIn#(Bit#(53)))  cLocal;
   interface PipeIn#(Bit#(53)) globalOut;
   interface Vector#(4, PipeOut#(Bit#(32))) interval;
   interface Reset rst;
   interface PipeIn#(Bit#(1)) isSwitch;
endinterface

interface SonicUserRequest;
   method Action dtp_read_version();
   method Action dtp_reset(Bit#(32) len);
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
   method Action dtp_read_delay(Bit#(8) port_no);
   method Action dtp_read_state(Bit#(8) port_no);
   method Action dtp_read_error(Bit#(8) port_no);
   method Action dtp_read_cnt(Bit#(8) cmd);
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) local_cnt);
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
   method Action dtp_read_local_cnt(Bit#(8) port_no);
   method Action dtp_read_global_cnt();
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
/* NOT IMPLEMENTED YET.
   method Action dtp_ctrl_disable();
   method Action dtp_ctrl_enable();
*/
endinterface

interface SonicUserIndication;
   method Action dtp_read_version_resp(Bit#(32) version);
   method Action dtp_read_delay_resp(Bit#(8) port_no, Bit#(32) delay);
   method Action dtp_read_state_resp(Bit#(8) port_no, Bit#(32) state);
   method Action dtp_read_error_resp(Bit#(8) port_no, Bit#(64) jumpc);
   method Action dtp_read_cnt_resp(Bit#(64) val);
   method Action dtp_logger_read_cnt_resp(Bit#(8) port_no, Bit#(64) localc, Bit#(64) msg1, Bit#(64) msg2);
   method Action dtp_read_local_cnt_resp(Bit#(8) port_no, Bit#(64) val);
   method Action dtp_read_global_cnt_resp(Bit#(64) val);
   method Action dtp_read_beacon_interval_resp(Bit#(8) port_no, Bit#(32) interval);
endinterface

interface SonicUser;
   interface SonicUserRequest request;
   interface DtpIfc           dtp;
endinterface

module mkSonicUser#(SonicUserIndication indication)(SonicUser);
   let verbose = False;
   Clock defaultClock <- exposeCurrentClock();

   Reg#(Bit#(64))  cycle_count <- mkReg(0);
   Reg#(Bit#(64))  last_count  <- mkReg(0);

   FIFOF#(Bit#(128)) cntFifo <- mkFIFOF();
   Reg#(Bit#(128))   cycle_reg <- mkReg(0);
   Reg#(Bit#(1))     isSwitch_reg <- mkReg(0);
   Vector#(4, Reg#(Bit#(32))) beacon_interval <- replicateM(mkReg(1000)); //default beacon interval is 1000.

   Vector#(4, FIFOF#(Bit#(53))) fromHostFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) toHostFifo   <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) delayFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) stateFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(64))) jumpCountFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) cLocalFifo   <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(53)) cGlobalFifo <- mkSizedFIFOF(4);
   Vector#(4, FIFOF#(Bit#(32))) intervalFifo <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(1)) isSwitchFifo <- mkFIFOF();

   Reg#(Bit#(8))  lwrite_port <- mkReg(0);
   FIFOF#(BufData) lwrite_data_cycle1 <- mkSizedFIFOF(8);
   FIFOF#(BufData) lwrite_data_cycle2 <- mkSizedFIFOF(8);
   FIFOF#(void) log_write_cf <- mkFIFOF;

   Vector#(4, FIFOF#(BufData)) lread_data_cycle1 <- replicateM(mkSizedFIFOF(8));
   Vector#(4, FIFOF#(BufData)) lread_data_cycle2 <- replicateM(mkSizedFIFOF(8));
   Vector#(4, FIFOF#(Bit#(53))) lread_data_timestamp <- replicateM(mkSizedFIFOF(8));

   Reg#(Bit#(28)) dtp_rst_cntr <- mkReg(0);
   MakeResetIfc dtpResetOut <- mkResetSync(0, False, defaultClock);

   rule count;
      cycle_count <= cycle_count + 1;
   endrule

   // clear all fifo on reset
   rule clearOnReset(dtpResetOut.isAsserted);
      for (Integer i=0; i<4; i=i+1) begin
         fromHostFifo[i].clear();
         toHostFifo[i].clear();
         delayFifo[i].clear();
         stateFifo[i].clear();
         jumpCountFifo[i].clear();
         cLocalFifo[i].clear();
         intervalFifo[i].clear();
         lread_data_cycle1[i].clear();
         lread_data_cycle2[i].clear();
         lread_data_timestamp[i].clear();
      end
      cGlobalFifo.clear();
      cntFifo.clear();
      lwrite_data_cycle1.clear();
      lwrite_data_cycle2.clear();
      log_write_cf.clear();
   endrule

   // dtp_read_cnt
   rule snapshot_dtp_timestamp;
      let v <- toGet(cntFifo).get;
      cycle_reg <= v;
   endrule

   // dtp_read_delay
   Vector#(4, Reg#(Bit#(32))) delay_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_delay;
         let v <- toGet(delayFifo[i]).get;
         delay_reg[i] <= v;
      endrule
   end

   // dtp_read_state
   Vector#(4, Reg#(Bit#(32))) state_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_state;
         let v <- toGet(stateFifo[i]).get;
         state_reg[i] <= v;
      endrule
   end

   // dtp_read_error
   Vector#(4, Reg#(Bit#(64))) jumpc_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_jumpc;
         let v <- toGet(jumpCountFifo[i]).get;
         jumpc_reg[i] <= v;
      endrule
   end

   // dtp_read_local_cnt
   Vector#(4, Reg#(Bit#(53))) clocal_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_clocal;
         let v <- toGet(cLocalFifo[i]).get;
         clocal_reg[i] <= v;
      endrule
   end

   // dtp_read_global_cnt
   Reg#(Bit#(53)) cglobal_reg <- mkReg(0);
   rule snapshot_cglobal;
      let v <- toGet(cGlobalFifo).get;
      cglobal_reg <= v;
   endrule

   // dtp_set_interval
   for (Integer i=0; i<4; i=i+1) begin
      rule set_interval;
         let v = beacon_interval[i];
         intervalFifo[i].enq(v);
      endrule
   end

   Integer chunk_a = 0;
   Integer chunk_b = 1;
   function Bit#(2) toState(Integer st);
      return (1<<st);
   endfunction

   Reg#(Bit#(2)) lwstate <- mkReg(toState(chunk_a));
   // dtp_logger_write_cnt
   rule log_from_host_cycle;
      if ((lwstate[chunk_a] == 1) && lwrite_data_cycle1.notEmpty) begin
         let v1 = lwrite_data_cycle1.first;
         if (fromHostFifo[v1.port_no].notFull) begin
            fromHostFifo[v1.port_no].enq({1'b0, truncate(v1.data)});
            lwrite_data_cycle1.deq;
            lwstate <= toState(chunk_b);
         end
      end
      else if((lwstate[chunk_b] == 1) && lwrite_data_cycle2.notEmpty) begin
         let v2 = lwrite_data_cycle2.first;
         if (fromHostFifo[v2.port_no].notFull) begin
            fromHostFifo[v2.port_no].enq({1'b1, truncate(v2.data)});
            lwrite_data_cycle2.deq;
            lwstate <= toState(chunk_a);
         end
      end
   endrule

   for (Integer i=0; i<4; i=i+1) begin
      rule save_host_data (toHostFifo[i].notEmpty);
         Bit#(53) v = toHostFifo[i].first;
         case (v[52]) matches
            0: begin
               lread_data_cycle1[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
            end
            1: begin
               lread_data_cycle2[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
               Bit#(53) timestamp = 0;
               if (isSwitch_reg == 0) begin // 0 for NIC, 1 for Switch
                  timestamp = clocal_reg[i];
               end
               else begin
                  timestamp = cglobal_reg;
               end
               lread_data_timestamp[i].enq(timestamp);
            end
         endcase
         toHostFifo[i].deq;
      endrule
   end

   rule assert_reset (dtp_rst_cntr > 0);
      dtpResetOut.assertReset;
      dtp_rst_cntr <= dtp_rst_cntr - 1;
   endrule

   rule switch_mode;
      let v <- toGet(isSwitchFifo).get;
      isSwitch_reg <= v;
   endrule

   // Interface to external modules.
   interface dtp = (interface DtpIfc;
      interface timestamp = toPipeIn(cntFifo);
      interface delay     = map(toPipeIn, delayFifo);
      interface state     = map(toPipeIn, stateFifo);
      interface jumpCount = map(toPipeIn, jumpCountFifo);
      interface toHost    = map(toPipeIn, toHostFifo);
      interface fromHost  = map(toPipeOut, fromHostFifo);
      interface cLocal    = map(toPipeIn, cLocalFifo);
      interface globalOut = toPipeIn(cGlobalFifo);
      interface interval  = map(toPipeOut, intervalFifo);
      interface rst       = dtpResetOut.new_rst;
      interface isSwitch  = toPipeIn(isSwitchFifo);
   endinterface);

   // API implementation
   interface SonicUserRequest request;
   method Action dtp_read_version();
      let v = `DtpVersion; //Defined in Makefile as time of compilation.
      indication.dtp_read_version_resp(v);
   endmethod
   method Action dtp_reset(Bit#(32) len) if (dtp_rst_cntr == 0);
      Bit#(28) limit = truncate(len) & 28'hFFFFFFF;
      if (limit < 32) begin
         limit = 32;
      end
      dtp_rst_cntr <= limit;
   endmethod
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
      //
   endmethod
   method Action dtp_read_delay(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_delay_resp(port_no, truncate(delay_reg[port_no]));
      end
   endmethod
   method Action dtp_read_state(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_state_resp(port_no, state_reg[port_no]);
      end
   endmethod
   method Action dtp_read_error(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_error_resp(port_no, jumpc_reg[port_no]);
      end
   endmethod
   method Action dtp_read_cnt(Bit#(8) port_no);
      indication.dtp_read_cnt_resp(truncate(cycle_reg));
   endmethod
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) host_timestamp);
      // Check valid port No.
      if (port_no < 4) begin
         lwrite_data_cycle1.enq(BufData{port_no: port_no, data: host_timestamp});
         lwrite_data_cycle2.enq(BufData{port_no: port_no, data: zeroExtend(clocal_reg[port_no])});
      end
   endmethod
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         if (lread_data_cycle1[port_no].notEmpty && lread_data_cycle2[port_no].notEmpty) begin
            Bit#(64) remote_message1 = lread_data_cycle1[port_no].first.data;
            Bit#(64) remote_message2 = lread_data_cycle2[port_no].first.data;
            Bit#(53) timestamp = lread_data_timestamp[port_no].first;
            indication.dtp_logger_read_cnt_resp(port_no,
                                                zeroExtend(timestamp),
                                                zeroExtend(remote_message1),
                                                zeroExtend(remote_message2));
            lread_data_cycle1[port_no].deq;
            lread_data_cycle2[port_no].deq;
            lread_data_timestamp[port_no].deq;
         end
      end
   endmethod
   method Action dtp_read_local_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_local_cnt_resp(port_no, zeroExtend(clocal_reg[port_no]));
      end
   endmethod
   method Action dtp_read_global_cnt();
      indication.dtp_read_global_cnt_resp(zeroExtend(cglobal_reg));
   endmethod
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
      if (port_no < 4) begin
         beacon_interval[port_no] <= interval;
      end
   endmethod
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_beacon_interval_resp(port_no, beacon_interval[port_no]);
      end
   endmethod
   endinterface
endmodule

// Copyright (c) 2015 Cornell University.

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

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

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

import Clocks::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import GetPut::*;
import Probe::*;

typedef struct {
   Bit#(8) port_no;
   Bit#(64) data;
} BufData deriving (Bits, Eq);

interface DtpIfc;
   interface PipeIn#(Bit#(128)) timestamp; // streaming time counter from NetTop.
   interface Vector#(4, PipeOut#(Bit#(53))) fromHost;
   interface Vector#(4, PipeIn#(Bit#(53)))  toHost;
   interface Vector#(4, PipeIn#(Bit#(32)))  delay;
   interface Vector#(4, PipeIn#(Bit#(32)))  state;
   interface Vector#(4, PipeIn#(Bit#(64)))  jumpCount;
   interface Vector#(4, PipeIn#(Bit#(53)))  cLocal;
   interface PipeIn#(Bit#(53)) globalOut;
   interface Vector#(4, PipeOut#(Bit#(32))) interval;
   interface Reset rst;
   interface PipeIn#(Bit#(1)) isSwitch;
endinterface

interface SonicUserRequest;
   method Action dtp_read_version();
   method Action dtp_reset(Bit#(32) len);
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
   method Action dtp_read_delay(Bit#(8) port_no);
   method Action dtp_read_state(Bit#(8) port_no);
   method Action dtp_read_error(Bit#(8) port_no);
   method Action dtp_read_cnt(Bit#(8) cmd);
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) local_cnt);
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
   method Action dtp_read_local_cnt(Bit#(8) port_no);
   method Action dtp_read_global_cnt();
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
/* NOT IMPLEMENTED YET.
   method Action dtp_ctrl_disable();
   method Action dtp_ctrl_enable();
*/
endinterface

interface SonicUserIndication;
   method Action dtp_read_version_resp(Bit#(32) version);
   method Action dtp_read_delay_resp(Bit#(8) port_no, Bit#(32) delay);
   method Action dtp_read_state_resp(Bit#(8) port_no, Bit#(32) state);
   method Action dtp_read_error_resp(Bit#(8) port_no, Bit#(64) jumpc);
   method Action dtp_read_cnt_resp(Bit#(64) val);
   method Action dtp_logger_read_cnt_resp(Bit#(8) port_no, Bit#(64) localc, Bit#(64) msg1, Bit#(64) msg2);
   method Action dtp_read_local_cnt_resp(Bit#(8) port_no, Bit#(64) val);
   method Action dtp_read_global_cnt_resp(Bit#(64) val);
   method Action dtp_read_beacon_interval_resp(Bit#(8) port_no, Bit#(32) interval);
endinterface

interface SonicUser;
   interface SonicUserRequest request;
   interface DtpIfc           dtp;
endinterface

module mkSonicUser#(SonicUserIndication indication)(SonicUser);
   let verbose = False;
   Clock defaultClock <- exposeCurrentClock();

   Reg#(Bit#(64))  cycle_count <- mkReg(0);
   Reg#(Bit#(64))  last_count  <- mkReg(0);

   FIFOF#(Bit#(128)) cntFifo <- mkFIFOF();
   Reg#(Bit#(128))   cycle_reg <- mkReg(0);
   Reg#(Bit#(1))     isSwitch_reg <- mkReg(0);
   Vector#(4, Reg#(Bit#(32))) beacon_interval <- replicateM(mkReg(1000)); //default beacon interval is 1000.

   Vector#(4, FIFOF#(Bit#(53))) fromHostFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) toHostFifo   <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) delayFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) stateFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(64))) jumpCountFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) cLocalFifo   <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(53)) cGlobalFifo <- mkSizedFIFOF(4);
   Vector#(4, FIFOF#(Bit#(32))) intervalFifo <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(1)) isSwitchFifo <- mkFIFOF();

   Reg#(Bit#(8))  lwrite_port <- mkReg(0);
   FIFOF#(BufData) lwrite_data_cycle1 <- mkSizedFIFOF(8);
   FIFOF#(BufData) lwrite_data_cycle2 <- mkSizedFIFOF(8);
   FIFOF#(void) log_write_cf <- mkFIFOF;

   Vector#(4, FIFOF#(BufData)) lread_data_cycle1 <- replicateM(mkSizedFIFOF(8));
   Vector#(4, FIFOF#(BufData)) lread_data_cycle2 <- replicateM(mkSizedFIFOF(8));
   Vector#(4, FIFOF#(Bit#(53))) lread_data_timestamp <- replicateM(mkSizedFIFOF(8));

   Reg#(Bit#(28)) dtp_rst_cntr <- mkReg(0);
   MakeResetIfc dtpResetOut <- mkResetSync(0, False, defaultClock);

   rule count;
      cycle_count <= cycle_count + 1;
   endrule

   // clear all fifo on reset
   rule clearOnReset(dtpResetOut.isAsserted);
      for (Integer i=0; i<4; i=i+1) begin
         fromHostFifo[i].clear();
         toHostFifo[i].clear();
         delayFifo[i].clear();
         stateFifo[i].clear();
         jumpCountFifo[i].clear();
         cLocalFifo[i].clear();
         intervalFifo[i].clear();
         lread_data_cycle1[i].clear();
         lread_data_cycle2[i].clear();
         lread_data_timestamp[i].clear();
      end
      cGlobalFifo.clear();
      cntFifo.clear();
      lwrite_data_cycle1.clear();
      lwrite_data_cycle2.clear();
      log_write_cf.clear();
   endrule

   // dtp_read_cnt
   rule snapshot_dtp_timestamp;
      let v <- toGet(cntFifo).get;
      cycle_reg <= v;
   endrule

   // dtp_read_delay
   Vector#(4, Reg#(Bit#(32))) delay_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_delay;
         let v <- toGet(delayFifo[i]).get;
         delay_reg[i] <= v;
      endrule
   end

   // dtp_read_state
   Vector#(4, Reg#(Bit#(32))) state_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_state;
         let v <- toGet(stateFifo[i]).get;
         state_reg[i] <= v;
      endrule
   end

   // dtp_read_error
   Vector#(4, Reg#(Bit#(64))) jumpc_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_jumpc;
         let v <- toGet(jumpCountFifo[i]).get;
         jumpc_reg[i] <= v;
      endrule
   end

   // dtp_read_local_cnt
   Vector#(4, Reg#(Bit#(53))) clocal_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_clocal;
         let v <- toGet(cLocalFifo[i]).get;
         clocal_reg[i] <= v;
      endrule
   end

   // dtp_read_global_cnt
   Reg#(Bit#(53)) cglobal_reg <- mkReg(0);
   rule snapshot_cglobal;
      let v <- toGet(cGlobalFifo).get;
      cglobal_reg <= v;
   endrule

   // dtp_set_interval
   for (Integer i=0; i<4; i=i+1) begin
      rule set_interval;
         let v = beacon_interval[i];
         intervalFifo[i].enq(v);
      endrule
   end

   // dtp_logger_write_cnt
   rule log_from_host_cycle1;
      let v = lwrite_data_cycle1.first;
      if (fromHostFifo[v.port_no].notFull) begin
         fromHostFifo[v.port_no].enq({1'b0, truncate(v.data)});
         log_write_cf.enq(?);
         lwrite_data_cycle1.deq;
      end
   endrule
   rule log_from_host_cycle2 (log_write_cf.notEmpty);
      let v = lwrite_data_cycle2.first;
      if (fromHostFifo[v.port_no].notFull) begin
         fromHostFifo[v.port_no].enq({1'b1, truncate(v.data)});
         lwrite_data_cycle2.deq;
         log_write_cf.deq;
      end
   endrule

   for (Integer i=0; i<4; i=i+1) begin
      rule save_host_data (toHostFifo[i].notEmpty && lread_data_cycle1[i].notFull &&
                           lread_data_cycle2[i].notFull && lread_data_timestamp[i].notFull);
         Bit#(53) v = toHostFifo[i].first;
         case (v[52]) matches
            0: begin
               lread_data_cycle1[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
            end
            1: begin
               lread_data_cycle2[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
               Bit#(53) timestamp = 0;
               if (isSwitch_reg == 0) begin // 0 for NIC, 1 for Switch
                  timestamp = clocal_reg[i];
               end
               else begin
                  timestamp = cglobal_reg;
               end
               lread_data_timestamp[i].enq(timestamp);
            end
         endcase
         toHostFifo[i].deq;
      endrule
   end

   rule assert_reset (dtp_rst_cntr != 0);
      dtp_rst_cntr <= dtp_rst_cntr - 1;
      dtpResetOut.assertReset;
   endrule

   rule switch_mode;
      let v <- toGet(isSwitchFifo).get;
      isSwitch_reg <= v;
   endrule

   // Interface to external modules.
   interface dtp = (interface DtpIfc;
      interface timestamp = toPipeIn(cntFifo);
      interface delay     = map(toPipeIn, delayFifo);
      interface state     = map(toPipeIn, stateFifo);
      interface jumpCount = map(toPipeIn, jumpCountFifo);
      interface toHost    = map(toPipeIn, toHostFifo);
      interface fromHost  = map(toPipeOut, fromHostFifo);
      interface cLocal    = map(toPipeIn, cLocalFifo);
      interface globalOut = toPipeIn(cGlobalFifo);
      interface interval  = map(toPipeOut, intervalFifo);
      interface rst       = dtpResetOut.new_rst;
      interface isSwitch  = toPipeIn(isSwitchFifo);
   endinterface);

   // API implementation
   interface SonicUserRequest request;
   method Action dtp_read_version();
      let v = `DtpVersion; //Defined in Makefile as time of compilation.
      indication.dtp_read_version_resp(v);
   endmethod
   method Action dtp_reset(Bit#(32) len);
      Bit#(28) limit = truncate(len) & 28'hFFFFFFF;
      if (limit == 0) limit = 32;
      dtp_rst_cntr <= limit;
   endmethod
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
      //
   endmethod
   method Action dtp_read_delay(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_delay_resp(port_no, truncate(delay_reg[port_no]));
      end
   endmethod
   method Action dtp_read_state(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_state_resp(port_no, state_reg[port_no]);
      end
   endmethod
   method Action dtp_read_error(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_error_resp(port_no, jumpc_reg[port_no]);
      end
   endmethod
   method Action dtp_read_cnt(Bit#(8) port_no);
      indication.dtp_read_cnt_resp(truncate(cycle_reg));
   endmethod
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) host_timestamp);
      // Check valid port No.
      if (port_no < 4) begin
         lwrite_data_cycle1.enq(BufData{port_no: port_no, data: host_timestamp});
         lwrite_data_cycle2.enq(BufData{port_no: port_no, data: zeroExtend(clocal_reg[port_no])});
      end
   endmethod
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         if (lread_data_cycle1[port_no].notEmpty && lread_data_cycle2[port_no].notEmpty) begin
            Bit#(64) remote_message1 = lread_data_cycle1[port_no].first.data;
            Bit#(64) remote_message2 = lread_data_cycle2[port_no].first.data;
            Bit#(53) timestamp = lread_data_timestamp[port_no].first;
            indication.dtp_logger_read_cnt_resp(port_no,
                                                zeroExtend(timestamp),
                                                zeroExtend(remote_message1),
                                                zeroExtend(remote_message2));
            lread_data_cycle1[port_no].deq;
            lread_data_cycle2[port_no].deq;
            lread_data_timestamp[port_no].deq;
         end
      end
   endmethod
   method Action dtp_read_local_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_local_cnt_resp(port_no, zeroExtend(clocal_reg[port_no]));
      end
   endmethod
   method Action dtp_read_global_cnt();
      indication.dtp_read_global_cnt_resp(zeroExtend(cglobal_reg));
   endmethod
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
      if (port_no < 4) begin
         beacon_interval[port_no] <= interval;
      end
   endmethod
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_beacon_interval_resp(port_no, beacon_interval[port_no]);
      end
   endmethod
   endinterface
endmodule


debug

debug

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

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

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

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

import Complex::*;
import FixedPoint::*;
import SDRTypes::*;
import FPCMult::*;
import Gearbox::*;
import Pipe::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import BRAMFIFO::*;
import Vector::*;
import Clocks::*;
import DefaultValue::*;
import DDS::*;

/* note rf signal is 64 bits wide, 2 sample of complex fixed point(0,16)
 */
(* always_enabled *)
interface ChannelSelect;
   interface PipeIn#(Vector#(2, Complex#(Signal))) rfreq;
   interface PipeOut#(Complex#(Signal)) ifreq;
   method Action setCoeff(Bit#(11) addr, Complex#(FixedPoint#(2,23)) value);
endinterface

module mkChannelSelect#(Bit#(10) decimation, DDS dds)(ChannelSelect);
   BRAM_Configure cfg = defaultValue;
   cfg.memorySize = 1024;
   BRAM2Port#(Bit#(10), Complex#(FixedPoint#(2,23))) coeffRam0 <-
       mkBRAM2Server(cfg);
   BRAM2Port#(Bit#(10), Complex#(FixedPoint#(2,23))) coeffRam1 <-
       mkBRAM2Server(cfg);
   Reg#(Bit#(10)) filterPhase <- mkReg(0);
   FIFO#(Bit#(1)) delayFilterPhase <- mkSizedFIFO(3);  // length > bram read latency
   FIFOF#(Vector#(2, Complex#(Signal))) infifo <- mkFIFOF();
   FIFOF#(Complex#(Signal)) outfifo <- mkFIFOF();
   Vector#(2, FPCMult) mul <- replicateM(mkFPCMult());
   Vector#(2, Reg#(Complex#(Product))) accum <- replicateM(mkReg(?));
   Vector#(2, FIFO#(Complex#(Product))) accumout <- replicateM(mkFIFO());
   FIFO#(Complex#(Product)) ycombined <- mkFIFO();
   FPCMult lo <- mkFPCMult();

   /* could do this with mkForkVector() but we don't need the extra FIFOs
      since everything is ready every cycle
    */
   rule duplicateSignal;
      let v = infifo.first;
      infifo.deq();
      mul[0].x.enq(v[0]);
      mul[1].x.enq(v[1]);
   endrule

   rule filter_phase;
      $display("filter_phase %d dec %d\n", filterPhase, decimation
);
      if (filterPhase == (decimation - 1))
	 begin
	    filterPhase <= 0;
	    delayFilterPhase.enq(1);
	 end
      else
	 begin
	    filterPhase <= filterPhase + 1;
	    delayFilterPhase.enq(0);
	 end
      coeffRam0.portB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: filterPhase, datain: ?});
      coeffRam1.portB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: filterPhase, datain: ?});
   endrule

   rule mulin;
      let c0 <- coeffRam0.portB.response.get();
      let c1 <- coeffRam1.portB.response.get();
      Bit#(1) phase = delayFilterPhase.first();
      $write("mulin ph %d c0 ", phase);
      $write(fshow(c0));
      $write(" c1 ");
      $write(fshow(c1));
      $write("\n");

      delayFilterPhase.deq();
      mul[0].a.enq(CoeffData{a: c0, filterPhase: phase});
      mul[1].a.enq(CoeffData{a: c1, filterPhase: phase});
   endrule

   rule muloutaccumin0;
      ProductData m = mul[0].y.first();
      mul[0].y.deq();
      if (m.filterPhase == 1)
	 begin
	    accum[0] <= m.y;
	    $write("muloutaccumin0 ph 1 ");
	    $display(fshow(m.y));
	    accumout[0].enq(accum[0]);
	 end
      else
	 begin
	    $write("muloutaccumin0 ph 0 ");
	    $display(fshow(m.y));
	    accum[0] <= accum[0] + m.y;
	 end
   endrule

   rule muloutaccumin1;
      ProductData m = mul[1].y.first();
      mul[1].y.deq();
      if (m.filterPhase == 1)
	 begin
	    $write("muloutaccumin1 ph 1 ");
	    $display(fshow(m.y));
	    accum[1] <= m.y;
	    accumout[1].enq(accum[1]);
	 end
      else
	 begin
	    $write("muloutaccumin0 ph 0 ");
	    $display(fshow(m.y));
	    accum[1] <= accum[1] + m.y;
	 end
   endrule

   rule accumoutcombinein;
      Complex#(Product) a0 = accumout[0].first();
      Complex#(Product) a1 = accumout[1].first();
      ycombined.enq(a0 + a1);
      accumout[0].deq();
      accumout[1].deq();
   endrule

   rule combineoutloin;
      Complex#(Product) yin = ycombined.first();
      FixedPoint#(2,16) yrel = fxptTruncate(yin.rel);
      FixedPoint#(2,16) yimg = fxptTruncate(yin.img);
      DDSOutType loin = dds.osc.first();
      dds.osc.deq();
      ycombined.deq();
      lo.x.enq(Complex{rel: yrel, img: yimg});
      lo.a.enq(CoeffData{a: loin, filterPhase: 0});
      $write("combineoutloin x ");
      $write(fshow(Complex{rel: yrel, img: yimg}));
      $write(" loin ");
      $display(fshow(loin));
   endrule

   rule loout;
      Complex#(Product) ifc = lo.y.first().y;
      FixedPoint#(2,16) ifrel = fxptTruncate(ifc.rel);
      FixedPoint#(2,16) ifimg = fxptTruncate(ifc.img);
      outfifo.enq(Complex{rel: ifrel, img: ifimg});
      lo.y.deq();
      $write("loout ");
      $display(fshow(Complex{rel: ifrel, img: ifimg}));
   endrule

   interface PipeIn rfreq = toPipeIn(infifo);

   method Action setCoeff(Bit#(11) addr, Complex#(FixedPoint#(2,23)) value);
      Bit#(1) idx = addr[0];
      if (idx == 0)
	 coeffRam0.portA.request.put(BRAMRequest{write: True, responseOnWrite: False, address: addr[10:1], datain: value});
      else
	 coeffRam1.portA.request.put(BRAMRequest{write: True, responseOnWrite: False, address: addr[10:1], datain: value});
   endmethod

   interface PipeOut ifreq = toPipeOut(outfifo);

endmodule

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

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

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

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

import Complex::*;
import FixedPoint::*;
import SDRTypes::*;
import FPCMult::*;
import Gearbox::*;
import Pipe::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import BRAMFIFO::*;
import Vector::*;
import Clocks::*;
import DefaultValue::*;
import DDS::*;

/* note rf signal is 64 bits wide, 2 sample of complex fixed point(0,16)
 */
(* always_enabled *)
interface ChannelSelect;
   interface PipeIn#(Vector#(2, Complex#(Signal))) rfreq;
   interface PipeOut#(Complex#(Signal)) ifreq;
   method Action setCoeff(Bit#(11) addr, Complex#(FixedPoint#(2,23)) value);
endinterface

module mkChannelSelect#(Bit#(10) decimation, DDS dds)(ChannelSelect);
   BRAM_Configure cfg = defaultValue;
   cfg.memorySize = 1024;
   BRAM2Port#(Bit#(10), Complex#(FixedPoint#(2,23))) coeffRam0 <-
       mkBRAM2Server(cfg);
   BRAM2Port#(Bit#(10), Complex#(FixedPoint#(2,23))) coeffRam1 <-
       mkBRAM2Server(cfg);
   Reg#(Bit#(10)) filterPhase <- mkReg(?);
   FIFO#(Bit#(1)) delayFilterPhase <- mkSizedFIFO(3);  // length > bram read latency
   FIFOF#(Vector#(2, Complex#(Signal))) infifo <- mkFIFOF();
   FIFOF#(Complex#(Signal)) outfifo <- mkFIFOF();
   Vector#(2, FPCMult) mul <- replicateM(mkFPCMult());
   Vector#(2, Reg#(Complex#(Product))) accum <- replicateM(mkReg(?));
   Vector#(2, FIFO#(Complex#(Product))) accumout <- replicateM(mkFIFO());
   FIFO#(Complex#(Product)) ycombined <- mkFIFO();
   FPCMult lo <- mkFPCMult();

   /* could do this with mkForkVector() but we don't need the extra FIFOs
      since everything is ready every cycle
    */
   rule duplicateSignal;
      let v = infifo.first;
      infifo.deq();
      mul[0].x.enq(v[0]);
      mul[1].x.enq(v[1]);
   endrule

   rule filter_phase;
      if (filterPhase == (decimation - 1))
	 begin
	    filterPhase <= 0;
	    delayFilterPhase.enq(1);
	 end
      else
	 begin
	    filterPhase <= filterPhase + 1;
	    delayFilterPhase.enq(0);
	 end
      coeffRam0.portB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: filterPhase, datain: ?});
      coeffRam1.portB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: filterPhase, datain: ?});
   endrule

   rule mulin;
      let c0 <- coeffRam0.portB.response.get();
      let c1 <- coeffRam1.portB.response.get();
      Bit#(1) phase = delayFilterPhase.first();
      $display ("mulin ph %d, c0.re %x c0.im %x, c1.re %x, c1.im %x\n",
	 phase, c0.rel, c0.img, c1.rel, c1.img);
      delayFilterPhase.deq();
      mul[0].a.enq(CoeffData{a: c0, filterPhase: phase});
      mul[1].a.enq(CoeffData{a: c1, filterPhase: phase});
   endrule

   rule muloutaccumin0;
      ProductData m = mul[0].y.first();
      mul[0].y.deq();
      if (m.filterPhase == 1)
	 begin
	    accum[0] <= m.y;
	    $display("muloutaccumin0 ph 1 pd.re %x pd.im %x\n",
	       m.y.rel, m.y.img);
	    accumout[0].enq(accum[0]);
	 end
      else
	 begin
	    $display("muloutaccumin0 ph 0 pd.re %x pd.im %x\n",
	       m.y.rel, m.y.img);
	    accum[0] <= accum[0] + m.y;
	 end
   endrule

   rule muloutaccumin1;
      ProductData m = mul[1].y.first();
      mul[1].y.deq();
      if (m.filterPhase == 1)
	 begin
	    $display("muloutaccumin1 ph 1 pd.re %x pd.im %x\n",
	       m.y.rel, m.y.img);
	    accum[1] <= m.y;
	    accumout[1].enq(accum[1]);
	 end
      else
	 begin
	    $display("muloutaccumin1 ph 0 pd.re %x pd.im %x\n",
	       m.y.rel, m.y.img);
	    accum[1] <= accum[1] + m.y;
	 end
   endrule

   rule accumoutcombinein;
      Complex#(Product) a0 = accumout[0].first();
      Complex#(Product) a1 = accumout[1].first();
      ycombined.enq(a0 + a1);
      accumout[0].deq();
      accumout[1].deq();
   endrule

   rule combineoutloin;
      Complex#(Product) yin = ycombined.first();
      FixedPoint#(2,16) yrel = fxptTruncate(yin.rel);
      FixedPoint#(2,16) yimg = fxptTruncate(yin.img);
      DDSOutType loin = dds.osc.first();
      dds.osc.deq();
      ycombined.deq();
      lo.x.enq(Complex{rel: yrel, img: yimg});
      lo.a.enq(CoeffData{a: loin, filterPhase: 0});
   endrule

   rule loout;
      Complex#(Product) ifc = lo.y.first().y;
      FixedPoint#(2,16) ifrel = fxptTruncate(ifc.rel);
      FixedPoint#(2,16) ifimg = fxptTruncate(ifc.img);
      outfifo.enq(Complex{rel: ifrel, img: ifimg});
      lo.y.deq();
   endrule

   interface PipeIn rfreq = toPipeIn(infifo);

   method Action setCoeff(Bit#(11) addr, Complex#(FixedPoint#(2,23)) value);
      Bit#(1) idx = addr[0];
      if (idx == 0)
	 coeffRam0.portA.request.put(BRAMRequest{write: True, responseOnWrite: False, address: addr[10:1], datain: value});
      else
	 coeffRam1.portA.request.put(BRAMRequest{write: True, responseOnWrite: False, address: addr[10:1], datain: value});
   endmethod

   interface PipeOut ifreq = toPipeOut(outfifo);

endmodule


fixed DmaVectorSource

fixed DmaVectorSource

Change-Id: I189bb5ddc7934110e58713514a342b0d2bb05b75

// 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 GetPut::*;
import FIFOF::*;
import PortalMemory::*;
import Dma::*;
import MemreadEngine::*;
import Adapter::*;
import BRAM::*;
import Pipe::*;

interface VectorSource#(numeric type dsz, type a);
   interface PipeOut#(a) pipe;
   method Action start(ObjectPointer h, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l);
   method ActionValue#(Bool) finish();
endinterface

interface DmaVectorSource#(numeric type dsz, type a);
   interface ObjectReadClient#(dsz) dmaClient;
   interface VectorSource#(dsz, a) vector;
endinterface

function ObjectReadClient#(asz) getSourceReadClient(DmaVectorSource#(asz,a) s); return s.dmaClient; endfunction
function ObjectWriteClient#(asz) getSinkWriteClient(DmaVectorSink#(asz,a) s); return s.dmaClient; endfunction
function VectorSource#(dsz, dtype) dmaVectorSourceVector(DmaVectorSource#(dsz,dtype) dmavs); return dmavs.vector; endfunction

module [Module] mkDmaVectorSource(DmaVectorSource#(asz, a))
   provisos (Bits#(a,asz),
	     Div#(asz,8,abytes),
	     Log#(abytes,ashift),
	     Mul#(abytes, 8, asz)
	     );

   Bool verbose = True;

   let asz = valueOf(asz);
   let abytes = valueOf(abytes);
   let ashift = valueOf(ashift);
   let burstLen = 1;

   FIFOF#(Bit#(asz)) dfifo <- mkSizedFIFOF(8);
   MemreadEngine#(asz) memreadEngine <- mkMemreadEngine(2, dfifo);

   interface ObjectReadClient dmaClient = memreadEngine.dmaClient;
   interface VectorSource vector;
       method Action start(ObjectPointer p, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l);
	  if (verbose) $display("DmaVectorSource.start h=%d a=%h l=%h ashift=%d", p, a, l, ashift);
          memreadEngine.start(p, a << ashift, truncate(l << ashift), 1 << ashift);
       endmethod
      method ActionValue#(Bool) finish();
	 let b <- memreadEngine.finish();
	 return b;
      endmethod
       interface PipeOut pipe;
	  method first();
	     return unpack(dfifo.first());
	  endmethod
	  method Action deq();
	     if (verbose) $display("ObjectReadClient pipe.deq() data=%h", dfifo.first);
	     dfifo.deq;
	  endmethod
	  method notEmpty = dfifo.notEmpty;
       endinterface
   endinterface
endmodule

interface VectorSink#(numeric type dsz, type a);
   interface PipeOut#(Bool) pipe;
   method Action start(ObjectPointer h, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l);
endinterface
interface DmaVectorSink#(numeric type dsz, type a);
   interface ObjectWriteClient#(dsz) dmaClient;
   interface VectorSink#(dsz, a) vector;
endinterface

module [Module] mkDmaVectorSink#(PipeOut#(a) pipe_in)(DmaVectorSink#(asz, a))
   provisos (Bits#(a,asz));

   let asz = valueOf(asz);
   let abytes = asz / 8;
   let burstLen = 1;

   Bool verbose = False;

   FIFOF#(Bool) rfifo <- mkFIFOF();
   Reg#(ObjectPointer) pointer <- mkReg(0);
   Reg#(Bit#(ObjectOffsetSize)) offset <- mkReg(0);
   Reg#(Bit#(ObjectOffsetSize)) doneoffset <- mkReg(0);
   Reg#(Bit#(ObjectOffsetSize)) limit <- mkReg(0);

   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	  method ActionValue#(ObjectRequest) get if (offset < limit && pipe_in.notEmpty());
	     if (verbose) $display("DmaVectorSink writeReq h=%d offset=%h burstlen=%d pipein.notEmpty=%d rfifo.notFull=%d", pointer, offset, burstLen, pipe_in.notEmpty(), rfifo.notFull());
	     offset <= offset + fromInteger(abytes)*burstLen;
	     return ObjectRequest { pointer: pointer, offset: offset, burstLen: burstLen, tag: 0 };
	  endmethod
      endinterface : writeReq
      interface Get writeData;
	 method ActionValue#(ObjectData#(asz)) get();
	    let v = pipe_in.first;
	    pipe_in.deq;
	    if (verbose) $display("DmaVectorSink.writeBack offset=%h v=%h", offset, v);
	    return ObjectData { data: pack(v), tag: 0 };
	 endmethod
      endinterface : writeData
      interface Put writeDone;
	 method Action put(Bit#(6) tag);
	    //$display("DmaVectorSink writeDone tag=%h", tag);
	    let da = doneoffset + fromInteger(abytes)*burstLen;
	    if (da >= limit)
	       rfifo.enq(?);
	    doneoffset <= da;
	 endmethod
      endinterface : writeDone
   endinterface : dmaClient

   interface VectorSink vector;
       method Action start(ObjectPointer h, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l) if (doneoffset >= limit);
	  pointer <= h;
	  offset <= a*fromInteger(abytes);
	  doneoffset <= a*fromInteger(abytes);
	  limit <= l*fromInteger(abytes);
	  if (verbose) $display("DmaVectorSink.start   h=%d offset=%h l=%h", h, a, l);
       endmethod
       interface PipeOut pipe = toPipeOut(rfifo);
   endinterface
endmodule

interface BramVectorSource#(numeric type addrsz, numeric type dsz, type dtype);
   interface BRAMClient#(Bit#(addrsz), dtype) bramClient;
   interface VectorSource#(dsz, dtype) vector;
endinterface

module [Module] mkBramVectorSource(BramVectorSource#(addrsz, dsz, dtype))
   provisos (Bits#(dtype,dsz),
	     Add#(a__, addrsz, ObjectOffsetSize)
	     );

   Bool verbose = False;

   let dsz = valueOf(dsz);

   FIFOF#(dtype) dfifo <- mkFIFOF();
   Reg#(Bit#(addrsz)) offset <- mkReg(0);
   Reg#(Bit#(addrsz)) limit <- mkReg(0);

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(Bit#(addrsz),dtype)) get() if (offset < limit);
	    if (verbose) $display("BramVectorSource.readReq offset=%h limit=%h", offset, limit);
	    offset <= offset + 1;
	    return BRAMRequest { write: False, responseOnWrite: False, address: offset, datain: unpack(0) };
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype dmaval);
	    if (verbose) $display("BramVectorSource.readData dmaval=%h", dmaval);
	    dfifo.enq(dmaval);
	 endmethod
      endinterface
   endinterface : bramClient
   interface VectorSource vector;
       method Action start(ObjectPointer pointer, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l) if (offset >= limit);
	  if (verbose) $display("BramVectorSource.start a=%h l=%h", a, l);
	  offset <= truncate(a);
	  limit <= truncate(l);
       endmethod
       interface PipeOut pipe;
	  method first = dfifo.first;
	  method Action deq();
	     if (verbose) $display("BramVectorSource pipe.deq() data=%h", dfifo.first);
	     dfifo.deq;
	  endmethod
	  method notEmpty = dfifo.notEmpty;
       endinterface
   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 GetPut::*;
import FIFOF::*;
import PortalMemory::*;
import Dma::*;
import MemreadEngine::*;
import Adapter::*;
import BRAM::*;
import Pipe::*;

interface VectorSource#(numeric type dsz, type a);
   interface PipeOut#(a) pipe;
   method Action start(ObjectPointer h, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l);
endinterface

interface DmaVectorSource#(numeric type dsz, type a);
   interface ObjectReadClient#(dsz) dmaClient;
   interface VectorSource#(dsz, a) vector;
endinterface

function ObjectReadClient#(asz) getSourceReadClient(DmaVectorSource#(asz,a) s); return s.dmaClient; endfunction
function ObjectWriteClient#(asz) getSinkWriteClient(DmaVectorSink#(asz,a) s); return s.dmaClient; endfunction
function VectorSource#(dsz, dtype) dmaVectorSourceVector(DmaVectorSource#(dsz,dtype) dmavs); return dmavs.vector; endfunction

module [Module] mkDmaVectorSource(DmaVectorSource#(asz, a))
   provisos (Bits#(a,asz),
	     Div#(asz,8,abytes),
	     Log#(abytes,ashift),
	     Mul#(abytes, 8, asz)
	     );

   Bool verbose = True;

   let asz = valueOf(asz);
   let abytes = valueOf(abytes);
   let ashift = valueOf(ashift);
   let burstLen = 1;

   FIFOF#(Bit#(asz)) dfifo <- mkFIFOF();
   MemreadEngine#(asz) memreadEngine <- mkMemreadEngine(2, dfifo);

   interface ObjectReadClient dmaClient = memreadEngine.dmaClient;
   interface VectorSource vector;
       method Action start(ObjectPointer p, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l);
	  if (verbose) $display("DmaVectorSource.start h=%d a=%h l=%h ashift=%d", p, a, l, ashift);
          memreadEngine.start(p, a, truncate(l << ashift), 8);
       endmethod
       interface PipeOut pipe;
	  method first();
	     return unpack(dfifo.first());
	  endmethod
	  method Action deq();
	     if (verbose) $display("ObjectReadClient pipe.deq() data=%h", dfifo.first);
	     dfifo.deq;
	  endmethod
	  method notEmpty = dfifo.notEmpty;
       endinterface
   endinterface
endmodule

interface VectorSink#(numeric type dsz, type a);
   interface PipeOut#(Bool) pipe;
   method Action start(ObjectPointer h, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l);
endinterface
interface DmaVectorSink#(numeric type dsz, type a);
   interface ObjectWriteClient#(dsz) dmaClient;
   interface VectorSink#(dsz, a) vector;
endinterface

module [Module] mkDmaVectorSink#(PipeOut#(a) pipe_in)(DmaVectorSink#(asz, a))
   provisos (Bits#(a,asz));

   let asz = valueOf(asz);
   let abytes = asz / 8;
   let burstLen = 1;

   Bool verbose = False;

   FIFOF#(Bool) rfifo <- mkFIFOF();
   Reg#(ObjectPointer) pointer <- mkReg(0);
   Reg#(Bit#(ObjectOffsetSize)) offset <- mkReg(0);
   Reg#(Bit#(ObjectOffsetSize)) doneoffset <- mkReg(0);
   Reg#(Bit#(ObjectOffsetSize)) limit <- mkReg(0);

   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	  method ActionValue#(ObjectRequest) get if (offset < limit && pipe_in.notEmpty());
	     if (verbose) $display("DmaVectorSink writeReq h=%d offset=%h burstlen=%d pipein.notEmpty=%d rfifo.notFull=%d", pointer, offset, burstLen, pipe_in.notEmpty(), rfifo.notFull());
	     offset <= offset + fromInteger(abytes)*burstLen;
	     return ObjectRequest { pointer: pointer, offset: offset, burstLen: burstLen, tag: 0 };
	  endmethod
      endinterface : writeReq
      interface Get writeData;
	 method ActionValue#(ObjectData#(asz)) get();
	    let v = pipe_in.first;
	    pipe_in.deq;
	    if (verbose) $display("DmaVectorSink.writeBack offset=%h v=%h", offset, v);
	    return ObjectData { data: pack(v), tag: 0 };
	 endmethod
      endinterface : writeData
      interface Put writeDone;
	 method Action put(Bit#(6) tag);
	    //$display("DmaVectorSink writeDone tag=%h", tag);
	    let da = doneoffset + fromInteger(abytes)*burstLen;
	    if (da >= limit)
	       rfifo.enq(?);
	    doneoffset <= da;
	 endmethod
      endinterface : writeDone
   endinterface : dmaClient

   interface VectorSink vector;
       method Action start(ObjectPointer h, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l) if (doneoffset >= limit);
	  pointer <= h;
	  offset <= a*fromInteger(abytes);
	  doneoffset <= a*fromInteger(abytes);
	  limit <= l*fromInteger(abytes);
	  if (verbose) $display("DmaVectorSink.start   h=%d offset=%h l=%h", h, a, l);
       endmethod
       interface PipeOut pipe = toPipeOut(rfifo);
   endinterface
endmodule

interface BramVectorSource#(numeric type addrsz, numeric type dsz, type dtype);
   interface BRAMClient#(Bit#(addrsz), dtype) bramClient;
   interface VectorSource#(dsz, dtype) vector;
endinterface

module [Module] mkBramVectorSource(BramVectorSource#(addrsz, dsz, dtype))
   provisos (Bits#(dtype,dsz),
	     Add#(a__, addrsz, ObjectOffsetSize)
	     );

   Bool verbose = False;

   let dsz = valueOf(dsz);

   FIFOF#(dtype) dfifo <- mkFIFOF();
   Reg#(Bit#(addrsz)) offset <- mkReg(0);
   Reg#(Bit#(addrsz)) limit <- mkReg(0);

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(Bit#(addrsz),dtype)) get() if (offset < limit);
	    if (verbose) $display("BramVectorSource.readReq offset=%h limit=%h", offset, limit);
	    offset <= offset + 1;
	    return BRAMRequest { write: False, responseOnWrite: False, address: offset, datain: unpack(0) };
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype dmaval);
	    if (verbose) $display("BramVectorSource.readData dmaval=%h", dmaval);
	    dfifo.enq(dmaval);
	 endmethod
      endinterface
   endinterface : bramClient
   interface VectorSource vector;
       method Action start(ObjectPointer pointer, Bit#(ObjectOffsetSize) a, Bit#(ObjectOffsetSize) l) if (offset >= limit);
	  if (verbose) $display("BramVectorSource.start a=%h l=%h", a, l);
	  offset <= truncate(a);
	  limit <= truncate(l);
       endmethod
       interface PipeOut pipe;
	  method first = dfifo.first;
	  method Action deq();
	     if (verbose) $display("BramVectorSource pipe.deq() data=%h", dfifo.first);
	     dfifo.deq;
	  endmethod
	  method notEmpty = dfifo.notEmpty;
       endinterface
   endinterface
endmodule


stop using 'output_reset' on FIFO18

stop using 'output_reset' on FIFO18

// 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 Action                 idelay_out(Bit#(1) v);
   method Bit#(1)                align_busy();
   method Bit#(1)                aligned();
   method Bit#(3)                samplein();
   method Bit#(3)                iodelay_reset_inc_ce();
   method Bit#(1)                bitslip();
   method Action                 autoalign(Bit#(1) v);
   method Action                 training(Bit#(10) v);
   method Action                 manual_tap(Bit#(10) v);
   method Action                 delay_wren(Bit#(1) v);
   method Action                 fifo_wren(Bit#(1) v);
   method Action                 reset(Bit#(1) v);
   method Bit#(1)                fifo_wren_sync();
   method Bit#(1)                fifo_reset();
   method Bit#(10)               dataout();
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Clock serdest, Clock not_clk, Clock host_clock)(Iserdesbvi);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   input_clock clk (CLK) = serdest;
   input_clock not_clk (not_clk) = not_clk;
   input_clock clkdiv (CLKDIV) = clkdiv;
   default_clock clock(CLOCK);
      method                  idelay_out(idelay_out) enable((*inhigh*) en14) clocked_by (clkdiv);
      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 ISERDES_BITSLIP_o  bitslip() clocked_by (clkdiv);
      method SAMPLEIN samplein() clocked_by (clock);
      method IODELAY_RESET_INC_CE_o iodelay_reset_inc_ce() clocked_by (clkdiv);
      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                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv);
      method FIFO_WREN_SYNC   fifo_wren_sync() clocked_by (clock);
      method FIFO_RESET       fifo_reset() clocked_by(clkdiv);
      method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv);
      method                  reset(RESET) enable((*inhigh*) en16) clocked_by (clkdiv);
      method FIFO_DATAOUT  dataout() clocked_by(clkdiv);
   schedule (fifo_reset, idelay_out, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip)
         CF (fifo_reset, idelay_out, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip);
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 (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

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();
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock, serdest, serdest_inverted.slowClock, defaultClock);
    //MakeResetIfc fifo_reset <- mkReset(2, True, serdes_clock);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    MakeResetIfc iodelay_reset <- mkReset(2, True, serdes_clock, clocked_by serdes_clock, reset_by serdes_reset);

    rule dfifo_reset_rule;
        dfifo.reset(serbvi.fifo_reset);
    endrule
    //rule fresetrule if (serbvi.fifo_reset == 1);
        //fifo_reset.assertReset();
    //endrule
    rule resetrule if (serbvi.iodelay_reset_inc_ce()[2] == 1);
        iodelay_reset.assertReset();
    endrule
    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, reset_by iodelay_reset.new_rst);

    rule delaye2_rule;
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(serbvi.iodelay_reset_inc_ce()[1] == 1);
        delaye2.ce(serbvi.iodelay_reset_inc_ce()[0]);
    endrule

    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, reset_by iodelay_reset.new_rst);
    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, reset_by iodelay_reset.new_rst);
    rule serdesdata_rule;
        let dout = 10'b0;
        master_data.d(0);
        //master_data.bitslip(serbvi.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);
        dout[0] = master_data.q1();
        dout[1] = master_data.q2();
        dout[2] = master_data.q3();
        dout[3] = master_data.q4();
        dout[4] = master_data.q5();
        dout[5] = master_data.q6();
        dout[6] = master_data.q7();
        dout[7] = master_data.q8();
        slave_data.d(0);
        //slave_data.bitslip(serbvi.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());
        dout[8] = slave_data.q3();
        dout[9] = slave_data.q4();
        slave_data.oclk(0);
        slave_data.oclkb(0);
        //serbvi.dataout(dout);
        //dfifo.di({6'b0,dout});
    endrule

    rule ssrule;
        serbvi.idelay_out(delaye2.dataout());
    endrule

    rule dfifo_ruledi;
        dfifo.di({6'b0,serbvi.dataout()});
    endrule

    rule wren_dfifo_rule;
        dfifo.wren(serbvi.fifo_wren_sync());
    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);
        serbvi.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        serbvi.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) 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 Action                 idelay_out(Bit#(1) v);
   method Bit#(1)                align_busy();
   method Bit#(1)                aligned();
   method Bit#(3)                samplein();
   method Bit#(3)                iodelay_reset_inc_ce();
   method Bit#(1)                bitslip();
   method Action                 autoalign(Bit#(1) v);
   method Action                 training(Bit#(10) v);
   method Action                 manual_tap(Bit#(10) v);
   method Action                 delay_wren(Bit#(1) v);
   method Action                 fifo_wren(Bit#(1) v);
   method Action                 reset(Bit#(1) v);
   method Bit#(1)                fifo_wren_sync();
   method Reset                  fifo_reset();
   method Bit#(10)               dataout();
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Clock serdest, Clock not_clk, Clock host_clock)(Iserdesbvi);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   input_clock clk (CLK) = serdest;
   input_clock not_clk (not_clk) = not_clk;
   input_clock clkdiv (CLKDIV) = clkdiv;
   default_clock clock(CLOCK);
      method                  idelay_out(idelay_out) enable((*inhigh*) en14) clocked_by (clkdiv);
      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 ISERDES_BITSLIP_o  bitslip() clocked_by (clkdiv);
      method SAMPLEIN samplein() clocked_by (clock);
      method IODELAY_RESET_INC_CE_o iodelay_reset_inc_ce() clocked_by (clkdiv);
      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                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv);
      method FIFO_WREN_SYNC   fifo_wren_sync() clocked_by (clock);
   output_reset fifo_reset(FIFO_RESET);
      method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv);
      method                  reset(RESET) enable((*inhigh*) en16) clocked_by (clkdiv);
      method FIFO_DATAOUT  dataout() clocked_by(clock);
   schedule (idelay_out, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip)
         CF (idelay_out, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip);
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 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;
    // reset RST;
    port DIP = 0;

    method          di(DI) enable((*inhigh*) en0) clocked_by (clock);
    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 (di, rden, wren, dataout, empty) CF (di, rden, wren, dataout, empty);
endmodule: mkFIFO18

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();
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock, serdest, serdest_inverted.slowClock, defaultClock);
    FIFO18 dfifo <- mkFIFO18(serdes_clock, reset_by serbvi.fifo_reset);
    MakeResetIfc iodelay_reset <- mkReset(2, True, serdes_clock, clocked_by serdes_clock, reset_by serdes_reset);

    rule resetrule if (serbvi.iodelay_reset_inc_ce()[2] == 1);
        iodelay_reset.assertReset();
    endrule
    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, reset_by iodelay_reset.new_rst);

    rule delaye2_rule;
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(serbvi.iodelay_reset_inc_ce()[1] == 1);
        delaye2.ce(serbvi.iodelay_reset_inc_ce()[0]);
    endrule

    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, reset_by iodelay_reset.new_rst);
    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, reset_by iodelay_reset.new_rst);
    rule serdesdata_rule;
        let dout = 10'b0;
        master_data.d(0);
        //master_data.bitslip(serbvi.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);
        dout[0] = master_data.q1();
        dout[1] = master_data.q2();
        dout[2] = master_data.q3();
        dout[3] = master_data.q4();
        dout[4] = master_data.q5();
        dout[5] = master_data.q6();
        dout[6] = master_data.q7();
        dout[7] = master_data.q8();
        slave_data.d(0);
        //slave_data.bitslip(serbvi.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());
        dout[8] = slave_data.q3();
        dout[9] = slave_data.q4();
        slave_data.oclk(0);
        slave_data.oclkb(0);
        //serbvi.dataout(dout);
        //dfifo.di({6'b0,dout});
    endrule

    rule ssrule;
        serbvi.idelay_out(delaye2.dataout());
    endrule

    rule dfifo_ruledi;
        dfifo.di({6'b0,serbvi.dataout()});
        dfifo.wren(serbvi.fifo_wren_sync());
    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);
        serbvi.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        serbvi.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) 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