clean up DTP.bsv

clean up DTP.bsv

// Copyright (c) 2014 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.

package Dtp;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;
//import MemTypes::*;

typedef 54 TIMESTAMP_LEN;
typedef 4  N_IFCs;

typedef 8  CmdLen;
typedef 32 ParamLen;

typedef 3 GLOBAL_DELAY;

typedef struct {
   Bit#(CmdLen)   cmd;
   Bit#(ParamLen) param;
} CmdTup deriving (Eq, Bits, FShow);

typedef struct {
   Bool     mux_sel;
   Bit#(53) c_local;
   Bit#(1)  parity;
} TxStageOneBuf deriving (Eq, Bits);

interface Dtp;
   interface PipeIn#(Bit#(66))  dtpRxIn;
   interface PipeIn#(Bit#(66))  dtpTxIn;
   interface PipeOut#(Bit#(66)) dtpRxOut;
   interface PipeOut#(Bit#(66)) dtpTxOut;
   (* always_ready, always_enabled *)
   method Action tx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   interface DtpToPhyIfc api;
endinterface

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;

//FIXME: should be controlled by driver.
typedef 1000 INIT_TIMEOUT;
typedef 1000 SYNC_TIMEOUT;

typedef enum {INIT, SENT, SYNC} DtpState
deriving (Bits, Eq);

(* synthesize *)
module mkDtpTop(Dtp);
   Dtp _a <- mkDtp(0);
   return _a;
endmodule

module mkDtp#(Integer id)(Dtp);

   let verbose = False;
   Wire#(Bool) tx_ready_wire <- mkDWire(False);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpRxInFifo <- mkFIFOF ();
   FIFOF#(Bit#(66)) dtpTxInFifo <- mkFIFOF ();

   Reg#(Bit#(1))   mode <- mkReg(0); // mode=0 NIC, mode=1 SWITCH
   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Reg#(DtpState)  curr_state  <- mkReg(INIT);

   Reg#(Bit#(53))  c_local <- mkReg(0); //fromInteger(c_local_init));
   Reg#(Bit#(53))  delay   <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_init <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_sync <- mkReg(0);
   Wire#(Bool) init_rcvd    <- mkDWire(False);
   Wire#(Bool) ack_rcvd     <- mkDWire(False);
   Wire#(Bool) beacon_rcvd  <- mkDWire(False);
   Reg#(Bool) is_idle      <- mkReg(False);

   Wire#(Bit#(53)) c_local_next <- mkDWire(0);
   Wire#(Bit#(2))  tx_mux_sel   <- mkDWire(0);

   // Tx Stage 1
   FIFOF#(Bit#(66)) dtpTxInPipelineFifo <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpTxOutFifo <- mkFIFOF;
   FIFOF#(TxStageOneBuf) stageOneFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) outstandingInitRequest <- mkSizedFIFOF(8);

   FIFOF#(Bit#(2))  dtpEventFifo   <- mkFIFOF;
   FIFOF#(Bit#(2))  dtpEventOutputFifo   <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) localCompareRemoteFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) localCompareGlobalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareGlobalFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareLocalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareRemoteFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareLocalFifo  <- mkFIFOF;

   FIFOF#(Bit#(53)) localOutputFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalOutputFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteOutputFifo <- mkFIFOF;

   FIFOF#(Bool) localLeRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) localGtRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) globalLeRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalGtRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalLeLocalFifo  <- mkFIFOF;
   FIFOF#(Bool) globalGtLocalFifo  <- mkFIFOF;

   FIFOF#(void) cfFifo <- mkFIFOF;
   FIFOF#(void) dmFifo <- mkFIFOF;

   Reg#(Bool)       log_rcvd     <- mkReg(False);
   FIFOF#(Bit#(53)) fromHostFifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(53)) toHostFifo   <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) delayFifo    <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) stateFifo     <- mkSizedFIFOF(1);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   // Setup link first if neither Tx or Rx is ready, bypass DTP.
   rule tx_bypass(!tx_ready_wire || !rx_ready_wire);
      let v <- toGet(dtpTxInFifo).get;
      dtpTxOutFifo.enq(v);
   endrule

   rule rx_bypass(!tx_ready_wire || !rx_ready_wire);
      let v <- toGet(dtpRxInFifo).get;
      dtpRxOutFifo.enq(v);
   endrule

   rule tx_stage1(tx_ready_wire && rx_ready_wire);
      let v <- toGet(dtpTxInFifo).get();
      Bit#(1) parity;
      Bool    mux_sel;
      Bit#(53) c_local_out;
      c_local_out = c_local+2; // forward compute parity.
      parity = ^c_local_out[52:0];

      if(v[9:2] == 8'h1e) begin
         mux_sel = True;
         is_idle <= True;
      end
      else begin
         mux_sel = False;
         is_idle <= False;
      end

      if(verbose) $display("%d: %d dtpTxIn=%h, c_local=%h, is_idle=%h, curr_state=%d", cycle, id, v, c_local, mux_sel, curr_state);
      cfFifo.enq(?);
      dmFifo.enq(?);
      stageOneFifo.enq(TxStageOneBuf{mux_sel: mux_sel,
                                     parity: parity,
                                     c_local: c_local+1});
      dtpTxInPipelineFifo.enq(v);
   endrule

   Probe#(Bit#(53)) debug_from_host <- mkProbe();
   rule tx_stage2(tx_ready_wire && rx_ready_wire);
      let val <- toGet(stageOneFifo).get;
      let v <- toGet(dtpTxInPipelineFifo).get();
      let mux_sel = val.mux_sel;
      let c_local = val.c_local;
      let parity = val.parity;

      Bit#(10) block_type;
      Bit#(66) encodeOut;
      Bit#(3) log_type    = fromInteger(valueOf(LOG_TYPE));
      Bit#(2) init_type   = fromInteger(valueOf(INIT_TYPE));
      Bit#(2) ack_type    = fromInteger(valueOf(ACK_TYPE));
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));

      block_type = v[9:0];

      if (mux_sel && tx_mux_sel == init_type) begin
         encodeOut = {c_local+1, parity, init_type, block_type};
         $display("Enqueued ougoing init request");
         outstandingInitRequest.enq(c_local+1);
      end
      else if (mux_sel && tx_mux_sel == ack_type) begin
         encodeOut = {c_local+1, parity, ack_type, block_type};
      end
      else if (mux_sel && tx_mux_sel == beacon_type) begin
         encodeOut = {c_local+1, parity, beacon_type, block_type};
      end
      else if (mux_sel && fromHostFifo.notEmpty) begin
         let host_data = fromHostFifo.first;
         debug_from_host <= host_data;
         encodeOut = {host_data, log_type, block_type};
         fromHostFifo.deq;
      end
      else begin
         encodeOut = v;
      end
      if(verbose) $display("%d: %d dtpTxOut=%h, c_local=%h, encodeOut=%h", cycle, id, v, c_local, encodeOut[11:10]);
      dtpTxOutFifo.enq(encodeOut);
   endrule

   // delay measurement
   rule delay_measurment(curr_state == INIT || curr_state == SENT);
      let init_timeout = fromInteger(valueOf(INIT_TIMEOUT));
      let init_type = fromInteger(valueOf(INIT_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      dmFifo.deq;
      // Timeout driven output
      if (timeout_count_init > init_timeout) begin
         if (is_idle) begin
            timeout_count_init <= 0;
         end
         else begin
            timeout_count_init <= timeout_count_init + 1;
         end
         tx_mux_sel <= init_type;
         if(verbose) $display("%d: %d, init timed_out %d", cycle, id, timeout_count_init);
      end
      else if (init_rcvd) begin
         timeout_count_init <= timeout_count_init + 1;
         tx_mux_sel <= ack_type;
      end
      else begin
         timeout_count_init <= timeout_count_init + 1;
         tx_mux_sel <= 2'b00;
      end

      // compute delay
      if (ack_rcvd) begin
         let temp = outstandingInitRequest.first;
         delay <= (c_local - temp - 1) >> 1;
         if(verbose) $display("%d: %d update delay=%h, %h, %h", cycle, id, c_local, temp, (c_local-temp-1)>>1);
         outstandingInitRequest.deq;
      end
   endrule

   // Beacon
   rule beacon(curr_state == SYNC);
      dmFifo.deq;
      let sync_timeout = fromInteger(valueOf(SYNC_TIMEOUT));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      if (timeout_count_sync >= sync_timeout) begin
         if (is_idle) begin
            timeout_count_sync <= 0;
         end
         else begin
            timeout_count_sync <= timeout_count_sync + 1;
         end
         tx_mux_sel <= beacon_type;
      end
      else if (init_rcvd) begin
         tx_mux_sel <= ack_type;
         timeout_count_sync <= timeout_count_sync + 1;
      end
      else begin
         timeout_count_sync <= timeout_count_sync + 1;
         tx_mux_sel <= 2'b00;
      end

      if (ack_rcvd) begin
         let temp = outstandingInitRequest.first;
         delay <= (c_local - temp - 1) >> 1;
         if(verbose) $display("%d: %d update delay=%h, %h, %h", cycle, id, c_local, temp, (c_local-temp-1)>>1);
         outstandingInitRequest.deq;
      end
   endrule

   // DTP state machine
   rule state_init (curr_state == INIT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (tx_mux_sel == init_type && is_idle) begin
         curr_state <= SENT;
      end
      else if (init_rcvd) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= INIT;
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
   endrule

   rule state_sent (curr_state == SENT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SENT;
      end
      else if (ack_rcvd) begin
         curr_state <= SYNC;
      end
      else if (tx_mux_sel == init_type) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= SENT;
      end
   endrule

   rule state_sync (curr_state == SYNC);
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SYNC;
      end
      else begin
         curr_state <= SYNC;
      end
   endrule

   Probe#(Bit#(53)) debug_to_host <- mkProbe();
   // Parse received DTP frame
   // Remove DTP timestamp before passing frame to MAC.
   rule rx_stage1(tx_ready_wire && rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      let v <- toGet(dtpRxInFifo).get();
      Bit#(1)  parity = ^v[65:13];
      Bit#(53) c_remote = v[65:13];
      Bit#(66) vo = v;
      Bool init_rcvd_next   = False;
      Bool ack_rcvd_next    = False;
      Bool beacon_rcvd_next = False;
      Bool log_rcvd_next    = False;
      vo[65:10] = 56'h0;

      if (v[9:2] == 8'h1e) begin
         if (v[11:10] == init_type) begin
            if (parity == v[12]) begin
               init_rcvd_next = True;
               //init_rcvd <= True;
               //ack_rcvd <= False;
               //beacon_rcvd <= False;
               //vo[65:10] = 56'h0;
               if(verbose) $display("%d: %d init_rcvd %h %h", cycle, id, c_remote, c_local);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == ack_type) begin
            if (parity == v[12]) begin
               ack_rcvd_next = True;
               //init_rcvd <= False;
               //ack_rcvd <= True;
               //beacon_rcvd <= False;
               //vo[65:10] = 56'h0;
               if(verbose) $display("%d: %d ack_rcvd %h %h", cycle, id, c_remote, c_local);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == beacon_type) begin
            if (parity == v[12]) begin
               beacon_rcvd_next = True;
               //init_rcvd <= False;
               //ack_rcvd <= False;
               //beacon_rcvd <= True;
               //vo[65:10] = 56'h0;
               localCompareRemoteFifo.enq(c_local + 1);
               remoteCompareLocalFifo.enq(c_remote + 1);
               if(verbose) $display("%d: %d beacon_rcvd %h %h", cycle, id, c_remote, c_local);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[12:10] == log_type) begin
            // send v[65:13] to logger.
            log_rcvd_next = True;
            //vo[65:10] = 56'h0;
            debug_to_host <= v[65:13];
            //FIXME: enable toHost.
            if (toHostFifo.notFull) begin
               toHostFifo.enq(v[65:13]);
            end
         end
//         else begin
//            init_rcvd <= False;
//            ack_rcvd <= False;
//            beacon_rcvd <= False;
//         end
         dtpEventFifo.enq(v[11:10]);
      end
      else begin
//         init_rcvd <= False;
//         ack_rcvd <= False;
//         beacon_rcvd <= False;
         dtpEventFifo.enq(2'b0);
      end
      //if(verbose) $display("%d: %d dtpRxIn=%h", cycle, id, v);
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
      init_rcvd   <= init_rcvd_next;
      ack_rcvd    <= ack_rcvd_next;
      beacon_rcvd <= beacon_rcvd_next;
      log_rcvd    <= log_rcvd_next;
      dtpRxOutFifo.enq(vo);
   endrule

   rule rx_stage2 (mode==0 || mode==1);
      let v_local <- toGet(localCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareLocalFifo).get();
      if(verbose) $display("%d: %d, v_local=%h, v_remote=%h, delay=%h", cycle, id, v_local, v_remote, delay);
      if (v_local + 1 <= v_remote + delay) begin
         localLeRemoteFifo.enq(True);
         localGtRemoteFifo.enq(False);
      end
      else begin
         localLeRemoteFifo.enq(False);
         localGtRemoteFifo.enq(True);
      end
      localOutputFifo.enq(v_local + 1);
      remoteOutputFifo.enq(v_remote + 1);
   endrule

   rule compare_global_remote (mode==1);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareGlobalFifo).get();
      if (v_global + global_delay <= v_remote + delay) begin
         globalLeRemoteFifo.enq(True);
         globalGtRemoteFifo.enq(False);
      end
      else begin
         globalLeRemoteFifo.enq(False);
         globalGtRemoteFifo.enq(True);
      end
      globalOutputFifo.enq(v_global);
   endrule

   rule compare_global_local (mode==1);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareLocalFifo).get();
      let v_local <- toGet(localCompareGlobalFifo).get();
      if (v_global + global_delay <= v_local + 1) begin
         globalLeLocalFifo.enq(True);
         globalGtLocalFifo.enq(False);
      end
      else begin
         globalLeLocalFifo.enq(False);
         globalGtLocalFifo.enq(True);
      end
   endrule

   rule rx_stage2_bypass;
      let v_event <- toGet(dtpEventFifo).get();
      dtpEventOutputFifo.enq(v_event);
   endrule

   rule rx_stage3_compute_c_local_next(mode==0);
      let vLocal <- toGet(localOutputFifo).get();
      let vRemote <- toGet(remoteOutputFifo).get();
      let useLocal <- toGet(localGtRemoteFifo).get();
      let _unused_ <- toGet(localLeRemoteFifo).get();
      if(verbose) $display("%d: %d, vLocal=%h", cycle, id, vLocal);
      if(verbose) $display("%d: %d, vRemote=%h", cycle, id, vRemote);
      if(verbose) $display("%d: %d, delay=%h", cycle, id, delay);
      if (useLocal) begin
         c_local_next <= vLocal + 1;
      end
      else begin
         c_local_next <= vRemote + delay + 1;
      end
   endrule

   rule output_switch (mode==1);
      let v_local <- toGet(localOutputFifo).get();
      let v_remote <- toGet(remoteOutputFifo).get();
      let v_global <- toGet(globalOutputFifo).get();
      let isGR <- toGet(globalGtRemoteFifo).get();
      let isGL <- toGet(globalGtLocalFifo).get();
      let isLR <- toGet(localGtRemoteFifo).get();
      let isLG <- toGet(globalLeLocalFifo).get();
      let isRG <- toGet(globalLeRemoteFifo).get();
      let isRL <- toGet(localLeRemoteFifo).get();
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      if (isGR && isGL) begin
         c_local_next <= v_global + global_delay;
      end
      else if (isLR && isLG) begin
         c_local_next <= v_local + 3;
      end
      else if (isRG && isRL) begin
         c_local_next <= v_remote + delay;
      end
   endrule

   rule rx_stage3;
      let v <- toGet(dtpEventOutputFifo).get();
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));
      if (v == beacon_type) begin
         c_local <= c_local_next;
         if(verbose) $display("%d: %d c_local_next = %h", cycle, id, c_local_next);
      end
      else begin
         c_local <= c_local + 1;
      end
   endrule

   rule export_delay;
      delayFifo.enq(truncate(delay));
   endrule

   rule export_state;
      stateFifo.enq(zeroExtend(pack(curr_state)));
   endrule

   method Action tx_ready(Bool v);
      tx_ready_wire <= v;
   endmethod

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   interface api = (interface DtpToPhyIfc;
      interface delayOut = toPipeOut(delayFifo);
      interface stateOut = toPipeOut(stateFifo);
      interface toHost   = toPipeOut(toHostFifo);
      interface fromHost = toPipeIn(fromHostFifo);
   endinterface);
   interface dtpRxIn = toPipeIn(dtpRxInFifo);
   interface dtpTxIn = toPipeIn(dtpTxInFifo);
   interface dtpRxOut = toPipeOut(dtpRxOutFifo);
   interface dtpTxOut = toPipeOut(dtpTxOutFifo);
endmodule
endpackage

// Copyright (c) 2014 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.

package Dtp;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;
//import MemTypes::*;

typedef 54 TIMESTAMP_LEN;
typedef 4  N_IFCs;

typedef 8  CmdLen;
typedef 32 ParamLen;

typedef 3 GLOBAL_DELAY;

typedef struct {
   Bit#(CmdLen)   cmd;
   Bit#(ParamLen) param;
} CmdTup deriving (Eq, Bits, FShow);

typedef struct {
   Bool     mux_sel;
   Bit#(53) c_local;
   Bit#(1)  parity;
} TxStageOneBuf deriving (Eq, Bits);

interface Dtp;
   interface PipeIn#(Bit#(66))  dtpRxIn;
   interface PipeIn#(Bit#(66))  dtpTxIn;
   interface PipeOut#(Bit#(66)) dtpRxOut;
   interface PipeOut#(Bit#(66)) dtpTxOut;
   (* always_ready, always_enabled *)
   method Action tx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
//   method Vector#(N_IFCs, Bit#(TIMESTAMP_LEN)) local_clock;
//   method Bit#(TIMESTAMP_LEN) global_clock;
//   interface PipeOut#(Bit#(53)) toHost;
//   interface PipeIn#(Bit#(53))  fromHost;
   interface DtpToPhyIfc api;
endinterface

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;

//FIXME: should be controlled by driver.
typedef 1000 INIT_TIMEOUT;
typedef 1000 SYNC_TIMEOUT;

typedef enum {INIT, SENT, SYNC} DtpState
deriving (Bits, Eq);

(* synthesize *)
module mkDtpTop(Dtp);
   Dtp _a <- mkDtp(0);
   return _a;
endmodule

module mkDtp#(Integer id)(Dtp);

   let verbose = False;
   Wire#(Bool) tx_ready_wire <- mkDWire(False);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpRxInFifo <- mkFIFOF ();
   FIFOF#(Bit#(66)) dtpTxInFifo <- mkFIFOF ();

   Reg#(Bit#(1))   mode <- mkReg(0); // mode=0 NIC, mode=1 SWITCH
   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Reg#(DtpState)  curr_state  <- mkReg(INIT);

   Reg#(Bit#(53))  c_local <- mkReg(0); //fromInteger(c_local_init));
   Reg#(Bit#(53))  delay   <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_init <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_sync <- mkReg(0);
   Wire#(Bool) init_rcvd    <- mkDWire(False);
   Wire#(Bool) ack_rcvd     <- mkDWire(False);
   Wire#(Bool) beacon_rcvd  <- mkDWire(False);
   Reg#(Bool) is_idle      <- mkReg(False);

   Wire#(Bit#(53)) c_local_next <- mkDWire(0);
   Wire#(Bit#(2))  tx_mux_sel   <- mkDWire(0);

   // Tx Stage 1
   FIFOF#(Bit#(66)) dtpTxInPipelineFifo <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpTxOutFifo <- mkFIFOF;
   FIFOF#(TxStageOneBuf) stageOneFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) outstandingInitRequest <- mkSizedFIFOF(8);

   FIFOF#(Bit#(2))  dtpEventFifo   <- mkFIFOF;
   FIFOF#(Bit#(2))  dtpEventOutputFifo   <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) localCompareRemoteFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) localCompareGlobalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareGlobalFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareLocalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareRemoteFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareLocalFifo  <- mkFIFOF;

   FIFOF#(Bit#(53)) localOutputFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalOutputFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteOutputFifo <- mkFIFOF;

   FIFOF#(Bool) localLeRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) localGtRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) globalLeRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalGtRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalLeLocalFifo  <- mkFIFOF;
   FIFOF#(Bool) globalGtLocalFifo  <- mkFIFOF;

   FIFOF#(void) cfFifo <- mkFIFOF;
   FIFOF#(void) dmFifo <- mkFIFOF;

   Reg#(Bool)       log_rcvd     <- mkReg(False);
   FIFOF#(Bit#(53)) fromHostFifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(53)) toHostFifo   <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) delayFifo    <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) stateFifo     <- mkSizedFIFOF(1);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   // Setup link first if neither Tx or Rx is ready, bypass DTP.
   rule tx_bypass(!tx_ready_wire || !rx_ready_wire);
      let v <- toGet(dtpTxInFifo).get;
      dtpTxOutFifo.enq(v);
   endrule

   rule rx_bypass(!tx_ready_wire || !rx_ready_wire);
      let v <- toGet(dtpRxInFifo).get;
      dtpRxOutFifo.enq(v);
   endrule

   rule tx_stage1(tx_ready_wire && rx_ready_wire);
      let v <- toGet(dtpTxInFifo).get();
      Bit#(1) parity;
      Bool    mux_sel;
      Bit#(53) c_local_out;
      c_local_out = c_local+2; // forward compute parity.
      parity = ^c_local_out[52:0];

      if(v[9:2] == 8'h1e) begin
         mux_sel = True;
         is_idle <= True;
      end
      else begin
         mux_sel = False;
         is_idle <= False;
      end

      if(verbose) $display("%d: %d dtpTxIn=%h, c_local=%h, is_idle=%h, curr_state=%d", cycle, id, v, c_local, mux_sel, curr_state);
      cfFifo.enq(?);
      dmFifo.enq(?);
      stageOneFifo.enq(TxStageOneBuf{mux_sel: mux_sel,
                                     parity: parity,
                                     c_local: c_local+1});
      dtpTxInPipelineFifo.enq(v);
   endrule

   Probe#(Bit#(53)) debug_from_host <- mkProbe();
   rule tx_stage2(tx_ready_wire && rx_ready_wire);
      let val <- toGet(stageOneFifo).get;
      let v <- toGet(dtpTxInPipelineFifo).get();
      let mux_sel = val.mux_sel;
      let c_local = val.c_local;
      let parity = val.parity;

      Bit#(10) block_type;
      Bit#(66) encodeOut;
      Bit#(3) log_type    = fromInteger(valueOf(LOG_TYPE));
      Bit#(2) init_type   = fromInteger(valueOf(INIT_TYPE));
      Bit#(2) ack_type    = fromInteger(valueOf(ACK_TYPE));
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));

      block_type = v[9:0];

      if (mux_sel && tx_mux_sel == init_type) begin
         encodeOut = {c_local+1, parity, init_type, block_type};
         $display("Enqueued ougoing init request");
         outstandingInitRequest.enq(c_local+1);
      end
      else if (mux_sel && tx_mux_sel == ack_type) begin
         encodeOut = {c_local+1, parity, ack_type, block_type};
      end
      else if (mux_sel && tx_mux_sel == beacon_type) begin
         encodeOut = {c_local+1, parity, beacon_type, block_type};
      end
      else if (mux_sel && fromHostFifo.notEmpty) begin
         let host_data = fromHostFifo.first;
         debug_from_host <= host_data;
         encodeOut = {host_data, log_type, block_type};
         fromHostFifo.deq;
      end
      else begin
         encodeOut = v;
      end
      if(verbose) $display("%d: %d dtpTxOut=%h, c_local=%h, encodeOut=%h", cycle, id, v, c_local, encodeOut[11:10]);
      dtpTxOutFifo.enq(encodeOut);
   endrule

   // delay measurement
   rule delay_measurment(curr_state == INIT || curr_state == SENT);
      let init_timeout = fromInteger(valueOf(INIT_TIMEOUT));
      let init_type = fromInteger(valueOf(INIT_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      dmFifo.deq;
      // Timeout driven output
      if (timeout_count_init > init_timeout) begin
         if (is_idle) begin
            timeout_count_init <= 0;
         end
         else begin
            timeout_count_init <= timeout_count_init + 1;
         end
         tx_mux_sel <= init_type;
         if(verbose) $display("%d: %d, init timed_out %d", cycle, id, timeout_count_init);
      end
      else if (init_rcvd) begin
         timeout_count_init <= timeout_count_init + 1;
         tx_mux_sel <= ack_type;
      end
      else begin
         timeout_count_init <= timeout_count_init + 1;
         tx_mux_sel <= 2'b00;
      end

      // compute delay
      if (ack_rcvd) begin
         let temp = outstandingInitRequest.first;
         delay <= (c_local - temp - 1) >> 1;
         if(verbose) $display("%d: %d update delay=%h, %h, %h", cycle, id, c_local, temp, (c_local-temp-1)>>1);
         outstandingInitRequest.deq;
      end
   endrule

   // Beacon
   rule beacon(curr_state == SYNC);
      dmFifo.deq;
      let sync_timeout = fromInteger(valueOf(SYNC_TIMEOUT));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      if (timeout_count_sync >= sync_timeout) begin
         if (is_idle) begin
            timeout_count_sync <= 0;
         end
         else begin
            timeout_count_sync <= timeout_count_sync + 1;
         end
         tx_mux_sel <= beacon_type;
      end
      else if (init_rcvd) begin
         tx_mux_sel <= ack_type;
         timeout_count_sync <= timeout_count_sync + 1;
      end
      else begin
         timeout_count_sync <= timeout_count_sync + 1;
         tx_mux_sel <= 2'b00;
      end

      if (ack_rcvd) begin
         let temp = outstandingInitRequest.first;
         delay <= (c_local - temp - 1) >> 1;
         if(verbose) $display("%d: %d update delay=%h, %h, %h", cycle, id, c_local, temp, (c_local-temp-1)>>1);
         outstandingInitRequest.deq;
      end
   endrule

   // DTP state machine
   rule state_init (curr_state == INIT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (tx_mux_sel == init_type && is_idle) begin
         curr_state <= SENT;
      end
      else if (init_rcvd) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= INIT;
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
   endrule

   rule state_sent (curr_state == SENT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SENT;
      end
      else if (ack_rcvd) begin
         curr_state <= SYNC;
      end
      else if (tx_mux_sel == init_type) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= SENT;
      end
   endrule

   rule state_sync (curr_state == SYNC);
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SYNC;
      end
      else begin
         curr_state <= SYNC;
      end
   endrule

   Probe#(Bit#(53)) debug_to_host <- mkProbe();
   // Parse received DTP frame
   // Remove DTP timestamp before passing frame to MAC.
   rule rx_stage1(tx_ready_wire && rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      let v <- toGet(dtpRxInFifo).get();
      Bit#(1)  parity = ^v[65:13];
      Bit#(53) c_remote = v[65:13];
      Bit#(66) vo = v;
      Bool init_rcvd_next   = False;
      Bool ack_rcvd_next    = False;
      Bool beacon_rcvd_next = False;
      Bool log_rcvd_next    = False;
      vo[65:10] = 56'h0;

      if (v[9:2] == 8'h1e) begin
         if (v[11:10] == init_type) begin
            if (parity == v[12]) begin
               init_rcvd_next = True;
               //init_rcvd <= True;
               //ack_rcvd <= False;
               //beacon_rcvd <= False;
               //vo[65:10] = 56'h0;
               if(verbose) $display("%d: %d init_rcvd %h %h", cycle, id, c_remote, c_local);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == ack_type) begin
            if (parity == v[12]) begin
               ack_rcvd_next = True;
               //init_rcvd <= False;
               //ack_rcvd <= True;
               //beacon_rcvd <= False;
               //vo[65:10] = 56'h0;
               if(verbose) $display("%d: %d ack_rcvd %h %h", cycle, id, c_remote, c_local);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[11:10] == beacon_type) begin
            if (parity == v[12]) begin
               beacon_rcvd_next = True;
               //init_rcvd <= False;
               //ack_rcvd <= False;
               //beacon_rcvd <= True;
               //vo[65:10] = 56'h0;
               localCompareRemoteFifo.enq(c_local + 1);
               remoteCompareLocalFifo.enq(c_remote + 1);
               if(verbose) $display("%d: %d beacon_rcvd %h %h", cycle, id, c_remote, c_local);
            end
            else begin
               $display("parity mismatch: expected %h, found %h", parity, v[12]);
            end
         end
         else if (v[12:10] == log_type) begin
            // send v[65:13] to logger.
            log_rcvd_next = True;
            //vo[65:10] = 56'h0;
            debug_to_host <= v[65:13];
            //FIXME: enable toHost.
            if (toHostFifo.notFull) begin
               toHostFifo.enq(v[65:13]);
            end
         end
//         else begin
//            init_rcvd <= False;
//            ack_rcvd <= False;
//            beacon_rcvd <= False;
//         end
         dtpEventFifo.enq(v[11:10]);
      end
      else begin
//         init_rcvd <= False;
//         ack_rcvd <= False;
//         beacon_rcvd <= False;
         dtpEventFifo.enq(2'b0);
      end
      //if(verbose) $display("%d: %d dtpRxIn=%h", cycle, id, v);
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
      init_rcvd   <= init_rcvd_next;
      ack_rcvd    <= ack_rcvd_next;
      beacon_rcvd <= beacon_rcvd_next;
      log_rcvd    <= log_rcvd_next;
      dtpRxOutFifo.enq(vo);
   endrule

   rule rx_stage2 (mode==0 || mode==1);
      let v_local <- toGet(localCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareLocalFifo).get();
      if(verbose) $display("%d: %d, v_local=%h, v_remote=%h, delay=%h", cycle, id, v_local, v_remote, delay);
      if (v_local + 1 <= v_remote + delay) begin
         localLeRemoteFifo.enq(True);
         localGtRemoteFifo.enq(False);
      end
      else begin
         localLeRemoteFifo.enq(False);
         localGtRemoteFifo.enq(True);
      end
      localOutputFifo.enq(v_local + 1);
      remoteOutputFifo.enq(v_remote + 1);
   endrule

   rule compare_global_remote (mode==1);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareGlobalFifo).get();
      if (v_global + global_delay <= v_remote + delay) begin
         globalLeRemoteFifo.enq(True);
         globalGtRemoteFifo.enq(False);
      end
      else begin
         globalLeRemoteFifo.enq(False);
         globalGtRemoteFifo.enq(True);
      end
      globalOutputFifo.enq(v_global);
   endrule

   rule compare_global_local (mode==1);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareLocalFifo).get();
      let v_local <- toGet(localCompareGlobalFifo).get();
      if (v_global + global_delay <= v_local + 1) begin
         globalLeLocalFifo.enq(True);
         globalGtLocalFifo.enq(False);
      end
      else begin
         globalLeLocalFifo.enq(False);
         globalGtLocalFifo.enq(True);
      end
   endrule

   rule rx_stage2_bypass;
      let v_event <- toGet(dtpEventFifo).get();
      dtpEventOutputFifo.enq(v_event);
   endrule

   rule rx_stage3_compute_c_local_next(mode==0);
      let vLocal <- toGet(localOutputFifo).get();
      let vRemote <- toGet(remoteOutputFifo).get();
      let useLocal <- toGet(localGtRemoteFifo).get();
      let _unused_ <- toGet(localLeRemoteFifo).get();
      if(verbose) $display("%d: %d, vLocal=%h", cycle, id, vLocal);
      if(verbose) $display("%d: %d, vRemote=%h", cycle, id, vRemote);
      if(verbose) $display("%d: %d, delay=%h", cycle, id, delay);
      if (useLocal) begin
         c_local_next <= vLocal + 1;
      end
      else begin
         c_local_next <= vRemote + delay + 1;
      end
   endrule

   rule output_switch (mode==1);
      let v_local <- toGet(localOutputFifo).get();
      let v_remote <- toGet(remoteOutputFifo).get();
      let v_global <- toGet(globalOutputFifo).get();
      let isGR <- toGet(globalGtRemoteFifo).get();
      let isGL <- toGet(globalGtLocalFifo).get();
      let isLR <- toGet(localGtRemoteFifo).get();
      let isLG <- toGet(globalLeLocalFifo).get();
      let isRG <- toGet(globalLeRemoteFifo).get();
      let isRL <- toGet(localLeRemoteFifo).get();
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      if (isGR && isGL) begin
         c_local_next <= v_global + global_delay;
      end
      else if (isLR && isLG) begin
         c_local_next <= v_local + 3;
      end
      else if (isRG && isRL) begin
         c_local_next <= v_remote + delay;
      end
   endrule

   rule rx_stage3;
      let v <- toGet(dtpEventOutputFifo).get();
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));
      if (v == beacon_type) begin
         c_local <= c_local_next;
         if(verbose) $display("%d: %d c_local_next = %h", cycle, id, c_local_next);
      end
      else begin
         c_local <= c_local + 1;
      end
   endrule

   rule export_delay;
      delayFifo.enq(truncate(delay));
   endrule

   rule export_state;
      stateFifo.enq(zeroExtend(pack(curr_state)));
   endrule

   method Action tx_ready(Bool v);
      tx_ready_wire <= v;
   endmethod

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   interface api = (interface DtpToPhyIfc;
      interface delayOut = toPipeOut(delayFifo);
      interface stateOut = toPipeOut(stateFifo);
      interface toHost   = toPipeOut(toHostFifo);
      interface fromHost = toPipeIn(fromHostFifo);
   endinterface);
   interface dtpRxIn = toPipeIn(dtpRxInFifo);
   interface dtpTxIn = toPipeIn(dtpTxInFifo);
   interface dtpRxOut = toPipeOut(dtpRxOutFifo);
   interface dtpTxOut = toPipeOut(dtpTxOutFifo);
endmodule
endpackage


fixed compilation error

fixed compilation error

// 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 FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import DmaVector::*;
import PortalMemory::*;
import Dma::*;
import FloatingPoint::*;
import Pipe::*;
import FloatOps::*;
import Timer::*;
import RbmTypes::*;

module [Module] mkDotProd#(PipeOut#(Vector#(n,Float)) xpipe, PipeOut#(Vector#(n,Float)) ypipe, UInt#(nwidth) numElts, UInt#(TLog#(n)) label)(PipeOut#(Float))
   provisos (
      Add#(1,a__,n),
      ReducePipe#(n,Float)
      );

   Bool verbose = False;

   PipeOut#(Tuple2#(Vector#(n,Float),Vector#(n,Float))) xypipe <- mkJoin(tuple2, xpipe, ypipe);

   Vector#(n, Server#(Tuple4#(Maybe#(Float), Float, Float, RoundMode), Tuple2#(Float,Exception))) macs <- replicateM(mkFloatMac);
   Vector#(n, FIFO#(Maybe#(Float))) accumFifo <- replicateM(mkFIFO());
   Reg#(UInt#(nwidth)) countInReg <- mkReg(0);
   Reg#(UInt#(nwidth)) countOutReg <- mkReg(0);
   FIFOF#(Vector#(n,Float)) resultFifo <- mkFIFOF();

   rule mul;
      let v = xypipe.first;
      xypipe.deq;
      let x = tpl_1(v);
      let y = tpl_2(v);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 Maybe#(Float) accum = tagged Invalid;
	 if (countInReg > 0) begin
	    accum = accumFifo[i].first();
	    accumFifo[i].deq();
	 end
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" dotprod x=") + fshow(x) + fshow(" y=") + fshow(y) + fshow(" accum=")+fshow(pack(accum))));
         macs[i].request.put(tuple4(accum, x[i], y[i], defaultValue));
	 if (i == 0) begin
	    let c = countInReg + fromInteger(valueOf(n));
	    if (c >= numElts)
	       c = 0;
	    countInReg <= c;
	 end
      end
   endrule

   rule macout;
      Vector#(n,Float) vs = unpack(0);
      let c = countOutReg + fromInteger(valueOf(n));
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 let resp <- macs[i].response.get();
	 vs[i] = tpl_1(resp);
	 if (c < numElts) begin
	    accumFifo[i].enq(tagged Valid tpl_1(resp));
	 end
      end
      if (c >= numElts) begin
	 Vector#(n,Bit#(32)) ivs = unpack(pack(vs));
	 resultFifo.enq(vs);
	 c = 0;
	 if (verbose) $display(fshow("label=")+fshow(label)+fshow(" countOutReg=")+fshow(countOutReg)+fshow(" numElts=")+fshow(numElts)+fshow(" mul=") + fshow(ivs));
      end
      countOutReg <= c;
   endrule

   PipeOut#(Vector#(n,Float)) resultPipe = toPipeOut(resultFifo);
   PipeOut#(Float) dotpipe <- mkReducePipe(mkFloatAddPipe, resultPipe);
   PipeOut#(Float) displaydotpipe = (interface PipeOut#(Float);
      method Float first(); return dotpipe.first(); endmethod
      method Action deq(); $display(fshow("label=")+fshow(label)+fshow(" dotpipe=")+fshow(dotpipe.first())); dotpipe.deq(); endmethod
      method Bool notEmpty(); return dotpipe.notEmpty(); endmethod
      endinterface);
   return dotpipe;
endmodule

typedef struct {
   a xbase;
   a xlimit;
   a xstep;
   a ybase;
   a ylimit;
   a ystep;
} XYRangeConfig#(type a) deriving (Bits, FShow);

interface XYRangePipeIfc#(type a);
   interface PipeOut#(Tuple2#(a,a)) pipe;
   method Action start(XYRangeConfig#(a) cfg);
   method Action display();
endinterface

module mkXYRangePipeOut(XYRangePipeIfc#(a)) provisos (Arith#(a), Bits#(a,awidth), Eq#(a), Ord#(a));
   Reg#(a) x <- mkReg(0);
   Reg#(a) y <- mkReg(0);
   Reg#(a) xbase <- mkReg(0);
   Reg#(a) ybase <- mkReg(0);
   Reg#(a) xstep <- mkReg(0);
   Reg#(a) ystep <- mkReg(0);
   Reg#(a) xlimit <- mkReg(0);
   Reg#(a) ylimit <- mkReg(0);

   interface PipeOut pipe;
      method Tuple2#(a,a) first() if (x < xlimit && y < ylimit);
	 return tuple2(x,y);
      endmethod
      method Action deq if (x < xlimit && y < ylimit);
	 let newx = x;
	 let newy = y+ystep;
	 if (newy >= ylimit && x < xlimit) begin
	    newy = ybase;
	    newx = newx + xstep;
	 end
	 x <= newx;
	 y <= newy;
      endmethod
      method Bool notEmpty();
	 return (x < xlimit && y < ylimit);
      endmethod
   endinterface
   method Action start(XYRangeConfig#(a) cfg) if (x >= xlimit);
      $display("XYRangePipe x=%d xlimit=%d xstep=%d y=%d ylimit=%d ystep=%d", cfg.xbase, cfg.xlimit, cfg.xstep, cfg.ybase, cfg.ylimit, cfg.ystep);
      x <= cfg.xbase;
      y <= cfg.ybase;
      xbase <= cfg.xbase;
      ybase <= cfg.ybase;
      xstep <= cfg.xstep;
      ystep <= cfg.ystep;
      xlimit <= cfg.xlimit;
      ylimit <= cfg.ylimit;
   endmethod
   method Action display();
      $display("XYRangePipe x=%d xlimit=%d y=%d ylimit=%d xstep=%d ystep=%d", x, xlimit, xstep, y, ylimit, ystep);
   endmethod
endmodule: mkXYRangePipeOut

typedef struct {
   ObjectPointer pointer;
   addrtype base;
   addrtype numRows;
   addrtype numColumns;
} MatrixDescriptor#(type addrtype) deriving (Bits);

// row major layout
interface DmaMatrixMultiplyIfc#(numeric type addrwidth, numeric type dsz);
   interface ObjectWriteClient#(dsz) dmaClient;
   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
endinterface

typedef enum {
   Idle, Ready, Running, Done
   } MMState deriving (Bits, Eq);

typedef 2 N;

module [Module] mkDmaMatrixMultiply#(Vector#(1, VectorSource#(dsz, Vector#(N, Float))) sourceA,
				     Vector#(N, VectorSource#(dsz, Vector#(N, Float))) sourceB,
				     function Module#(DmaVectorSink#(dsz, Vector#(N, Float))) mkSink(PipeOut#(Vector#(N, Float)) pipe_in)
				     )(DmaMatrixMultiplyIfc#(addrwidth, dsz))
   provisos (Add#(a__,ObjectOffsetSize,addrwidth)
	     , Add#(N,0,n)
	     , FShow#(Float)
	     , Arith#(Float)
	     , Bits#(Vector#(N, Float), dsz));

   let n = valueOf(n);
   Bool verbose = True;

   Reg#(Bool) doneReg <- mkReg(False);
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorA <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorB <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorC <- mkReg(unpack(0));
   Reg#(UInt#(addrwidth)) dotprodCount <- mkReg(0);

   Vector#(n, PipeOut#(Vector#(N,Float))) aPipes <- mkForkVector(sourceA[0].pipe);

   function Module#(PipeOut#(Float)) mkFxDotProd(Integer i);
      return mkDotProd(aPipes[i], sourceB[i].pipe, descriptorA.numColumns, fromInteger(i));
   endfunction
   Vector#(n, PipeOut#(Float)) fxdotprods <- genWithM(mkFxDotProd);

   FIFOF#(Vector#(N,Float)) dfifo <- mkFIFOF();
   let sinkC <- mkSink(toPipeOut(dfifo));

   XYRangePipeIfc#(UInt#(addrwidth)) xypipeifc <- mkXYRangePipeOut();

   Vector#(TAdd#(n,1), PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth)))) xypipes <- mkForkVector(xypipeifc.pipe);

   Reg#(Bool) running <- mkReg(False);
   FIFOF#(Bool) doneFifo <- mkFIFOF();

   Reg#(UInt#(32)) cycles <- mkReg(0);
   rule countCycles;
      cycles <= cycles+1;
   endrule

   for (Integer i = 0; i < n; i = i + 1) begin
      rule startDotProd;
	  Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[i].first;
	  xypipes[i].deq();

	  let row = tpl_1(xy);
	  let col = tpl_2(xy)+fromInteger(i);

	  let startA = row*descriptorA.numColumns; // row major
	  let startB = col*descriptorB.numColumns; // col major layout (pre-transposed)
	  let startC = row*descriptorC.numColumns + col; // row major
	 if (verbose) $display($format(fshow(cycles)+fshow("    startDotProd xy=")+fshow(tuple2(row,col))
				       +fshow(" startA=")+fshow(startA)
				       +fshow(" startB=")+fshow(startB)
				       +fshow(" startC=")+fshow(startC)));

	  if (i == 0) begin
	     sourceA[0].start(descriptorA.pointer, pack(truncate(startA)), pack(truncate(startA + descriptorA.numColumns)));
	     $display($format(fshow(cycles)+fshow("    sourceA[0].start")+fshow(startA)));
	  end
	 sourceB[i].start(descriptorB.pointer, pack(truncate(startB)), pack(truncate(startB + descriptorB.numColumns)));
	 UInt#(TLog#(n)) in = fromInteger(i);
	 $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].start")+fshow(startB)));
	  if (i == 0)
	     sinkC.vector.start(descriptorC.pointer, pack(truncate(startC)), pack(truncate(startC + fromInteger(n))));
       endrule
       if (i == 0)
	  rule finishSourceA;
	     $display($format(fshow(cycles)+fshow("    sourceA[0].finish ")));
	     let b <- sourceA[0].finish();
	  endrule
      rule finishSourceB;
	 UInt#(TLog#(n)) in = fromInteger(i);
	 $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].finish")));
	 let b <- sourceB[i].finish();
      endrule

   end

   rule dotProdValue;
      Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[n].first;
      xypipes[n].deq;
      Vector#(N,Float) vs;
      for (Integer i = 0; i < n; i = i + 1) begin
	 let v = fxdotprods[i].first;
	 fxdotprods[i].deq;
	 let xyi = tuple2(tpl_1(xy), tpl_2(xy)+fromInteger(i));
	 if (verbose) $display($format(fshow(cycles)+fshow("    dotprodvalue xy=")+fshow(xyi)+fshow(" dotprod=")+fshow(v)));
	 vs[i] = v;
      end
      dfifo.enq(vs);
   endrule

   rule sinkDone;
      // each time we write a burst of k values via sinkC
      let b <- sinkC.vector.finish();
      let c = dotprodCount-fromInteger(n);
      $display($format(fshow(cycles)+fshow("    sinkDone c")+fshow(c)));
      dotprodCount <= c;
      if (c == 0) begin
	 running <= False;
	 doneFifo.enq(?);
      end
   endrule

   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC) if (dotprodCount == 0);
      XYRangeConfig#(UInt#(addrwidth)) xycfg = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
							      ybase: 0, ylimit: numRowsB, ystep: fromInteger(n) };
      descriptorA <= MatrixDescriptor { pointer: pointerA, base: 0, numRows: numRowsA, numColumns: numColumnsA};
      descriptorB <= MatrixDescriptor { pointer: pointerB, base: 0, numRows: numRowsB, numColumns: numColumnsB};
      descriptorC <= MatrixDescriptor { pointer: pointerC, base: 0, numRows: numRowsA, numColumns: numRowsB};
      dotprodCount <= numRowsA*numRowsB;

      $display("mm pointerA=%d pointerB=%d pointerC=%d\n", pointerA, pointerB, pointerC);
      if (verbose) $display("mm.start ra=%d ca=%d rb=%d cb=%d dotprodCount=%d", numRowsA, numColumnsA, numRowsB, numColumnsB, dotprodCount);
      if (verbose) $display($format(fshow("mm.start ")+fshow(xycfg)));
      xypipeifc.start(xycfg);
   endmethod
   method ActionValue#(Bool) finish();
      $display("mm.finish()");
      doneFifo.deq();
      return True;
   endmethod

   interface ObjectWriteClient dmaClient = sinkC.dmaClient;
endmodule

interface DramMatrixMultiply#(numeric type n, numeric type dmasz);
   interface Vector#(TAdd#(N,1), ObjectReadClient#(dmasz)) readClients;
   interface Vector#(1, ObjectWriteClient#(dmasz)) writeClients;
   method Action start(ObjectPointer pointerA, UInt#(ObjectOffsetSize) numRowsA, UInt#(ObjectOffsetSize) numColumnsA,
		       ObjectPointer pointerB, UInt#(ObjectOffsetSize) numRowsB, UInt#(ObjectOffsetSize) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
   method Bit#(32) dbg();
endinterface

(* synthesize *)
module [Module] mkDramMatrixMultiply(DramMatrixMultiply#(N,TMul#(N,32)));
   Vector#(TAdd#(N,1), DmaVectorSource#(DmaSz, Vector#(N,Float))) vfsources <- replicateM(mkDmaVectorSource());
   Vector#(1, VectorSource#(DmaSz, Vector#(N,Float))) xvfsources = cons(vfsources[0].vector, nil);
   Vector#(N, VectorSource#(DmaSz, Vector#(N,Float))) yvfsources = takeAt(1, map(dmaVectorSourceVector, vfsources));
   DmaMatrixMultiplyIfc#(ObjectOffsetSize,DmaSz) dmaMMF <- mkDmaMatrixMultiply(xvfsources, yvfsources, mkDmaVectorSink);
   interface Vector readClients = map(getSourceReadClient, vfsources);
   interface Vector writeClients = cons(dmaMMF.dmaClient, nil);
   method start = dmaMMF.start;
   method finish = dmaMMF.finish;
   method Bit#(32) dbg();
      Bit#(32) d = 0;
      d[0] = pack(vfsources[0].vector.pipe.notEmpty());
      d[1] = pack(vfsources[1].vector.pipe.notEmpty());
      return d;
   endmethod
endmodule

interface Mm#(numeric type n);
   interface MmRequest mmRequest;
   interface TimerRequest timerRequest;
   interface Vector#(TAdd#(1,N), ObjectReadClient#(TMul#(32,N))) readClients;
   interface Vector#(1, ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module [Module] mkMm#(MmIndication ind, TimerIndication timerInd)(Mm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz)
      );

   let n = valueOf(n);

   DramMatrixMultiply#(N, TMul#(N,32)) dmaMMF <- mkDramMatrixMultiply();

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   rule mmfDone;
      $display("mmfDone");
      let d <- dmaMMF.finish();
      busyFifo.deq();
      ind.mmfDone();
   endrule

   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   interface TimerRequest timerRequest;
         method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface

   interface MmRequest mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3);
	 dmaMMF.start(h1, unpack(extend(r1)), unpack(extend(c1)),
		      h2, unpack(extend(r2)), unpack(extend(c2)),
		      h3);
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface Vector readClients = dmaMMF.readClients;
   interface Vector writeClients =  dmaMMF.writeClients;

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 FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import BRAM::*;
import DmaVector::*;
import PortalMemory::*;
import Dma::*;
import FloatingPoint::*;
import Pipe::*;
import FloatOps::*;
import Timer::*;
import RbmTypes::*;

module [Module] mkDotProd#(PipeOut#(Vector#(n,Float)) xpipe, PipeOut#(Vector#(n,Float)) ypipe, UInt#(nwidth) numElts, UInt#(TLog#(n)) label)(PipeOut#(Float))
   provisos (
      Add#(1,a__,n),
      ReducePipe#(n,Float)
      );

   Bool verbose = False;

   PipeOut#(Tuple2#(Vector#(n,Float),Vector#(n,Float))) xypipe <- mkJoin(tuple2, xpipe, ypipe);

   Vector#(n, Server#(Tuple4#(Maybe#(Float), Float, Float, RoundMode), Tuple2#(Float,Exception))) macs <- replicateM(mkFloatMac);
   Vector#(n, FIFO#(Maybe#(Float))) accumFifo <- replicateM(mkFIFO());
   Reg#(UInt#(nwidth)) countInReg <- mkReg(0);
   Reg#(UInt#(nwidth)) countOutReg <- mkReg(0);
   FIFOF#(Vector#(n,Float)) resultFifo <- mkFIFOF();

   rule mul;
      let v = xypipe.first;
      xypipe.deq;
      let x = tpl_1(v);
      let y = tpl_2(v);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 Maybe#(Float) accum = tagged Invalid;
	 if (countInReg > 0) begin
	    accum = accumFifo[i].first();
	    accumFifo[i].deq();
	 end
	 if (verbose) $display($format(fshow("label=")+fshow(label)+fshow(" dotprod x=") + fshow(x) + fshow(" y=") + fshow(y) + fshow(" accum=")+fshow(pack(accum))));
         macs[i].request.put(tuple4(accum, x[i], y[i], defaultValue));
	 if (i == 0) begin
	    let c = countInReg + fromInteger(valueOf(n));
	    if (c >= numElts)
	       c = 0;
	    countInReg <= c;
	 end
      end
   endrule

   rule macout;
      Vector#(n,Float) vs = unpack(0);
      let c = countOutReg + fromInteger(valueOf(n));
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 let resp <- macs[i].response.get();
	 vs[i] = tpl_1(resp);
	 if (c < numElts) begin
	    accumFifo[i].enq(tagged Valid tpl_1(resp));
	 end
      end
      if (c >= numElts) begin
	 Vector#(n,Bit#(32)) ivs = unpack(pack(vs));
	 resultFifo.enq(vs);
	 c = 0;
	 if (verbose) $display(fshow("label=")+fshow(label)+fshow(" countOutReg=")+fshow(countOutReg)+fshow(" numElts=")+fshow(numElts)+fshow(" mul=") + fshow(ivs));
      end
      countOutReg <= c;
   endrule

   PipeOut#(Vector#(n,Float)) resultPipe = toPipeOut(resultFifo);
   PipeOut#(Float) dotpipe <- mkReducePipe(mkFloatAddPipe, resultPipe);
   PipeOut#(Float) displaydotpipe = (interface PipeOut#(Float);
      method Float first(); return dotpipe.first(); endmethod
      method Action deq(); $display(fshow("label=")+fshow(label)+fshow(" dotpipe=")+fshow(dotpipe.first())); dotpipe.deq(); endmethod
      method Bool notEmpty(); return dotpipe.notEmpty(); endmethod
      endinterface);
   return dotpipe;
endmodule

typedef struct {
   a xbase;
   a xlimit;
   a xstep;
   a ybase;
   a ylimit;
   a ystep;
} XYRangeConfig#(type a) deriving (Bits, FShow);

interface XYRangePipeIfc#(type a);
   interface PipeOut#(Tuple2#(a,a)) pipe;
   method Action start(XYRangeConfig#(a) cfg);
   method Action display();
endinterface

module mkXYRangePipeOut(XYRangePipeIfc#(a)) provisos (Arith#(a), Bits#(a,awidth), Eq#(a), Ord#(a));
   Reg#(a) x <- mkReg(0);
   Reg#(a) y <- mkReg(0);
   Reg#(a) xbase <- mkReg(0);
   Reg#(a) ybase <- mkReg(0);
   Reg#(a) xstep <- mkReg(0);
   Reg#(a) ystep <- mkReg(0);
   Reg#(a) xlimit <- mkReg(0);
   Reg#(a) ylimit <- mkReg(0);

   interface PipeOut pipe;
      method Tuple2#(a,a) first() if (x < xlimit && y < ylimit);
	 return tuple2(x,y);
      endmethod
      method Action deq if (x < xlimit && y < ylimit);
	 let newx = x;
	 let newy = y+ystep;
	 if (newy >= ylimit && x < xlimit) begin
	    newy = ybase;
	    newx = newx + xstep;
	 end
	 x <= newx;
	 y <= newy;
      endmethod
      method Bool notEmpty();
	 return (x < xlimit && y < ylimit);
      endmethod
   endinterface
   method Action start(XYRangeConfig#(a) cfg) if (x >= xlimit);
      $display("XYRangePipe x=%d xlimit=%d xstep=%d y=%d ylimit=%d ystep=%d", cfg.xbase, cfg.xlimit, cfg.xstep, cfg.ybase, cfg.ylimit, cfg.ystep);
      x <= cfg.xbase;
      y <= cfg.ybase;
      xbase <= cfg.xbase;
      ybase <= cfg.ybase;
      xstep <= cfg.xstep;
      ystep <= cfg.ystep;
      xlimit <= cfg.xlimit;
      ylimit <= cfg.ylimit;
   endmethod
   method Action display();
      $display("XYRangePipe x=%d xlimit=%d y=%d ylimit=%d xstep=%d ystep=%d", x, xlimit, xstep, y, ylimit, ystep);
   endmethod
endmodule: mkXYRangePipeOut

typedef struct {
   ObjectPointer pointer;
   addrtype base;
   addrtype numRows;
   addrtype numColumns;
} MatrixDescriptor#(type addrtype) deriving (Bits);

// row major layout
interface DmaMatrixMultiplyIfc#(numeric type addrwidth, numeric type dsz);
   interface ObjectWriteClient#(dsz) dmaClient;
   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
endinterface

typedef enum {
   Idle, Ready, Running, Done
   } MMState deriving (Bits, Eq);

typedef 2 N;

module [Module] mkDmaMatrixMultiply#(Vector#(1, VectorSource#(dsz, Vector#(N, Float))) sourceA,
				     Vector#(N, VectorSource#(dsz, Vector#(N, Float))) sourceB,
				     function Module#(DmaVectorSink#(dsz, Vector#(N, Float))) mkSink(PipeOut#(Vector#(N, Float)) pipe_in)
				     )(DmaMatrixMultiplyIfc#(addrwidth, dsz))
   provisos (Add#(a__,ObjectOffsetSize,addrwidth)
	     , Add#(N,0,n)
	     , FShow#(Float)
	     , Arith#(Float)
	     , Bits#(Vector#(N, Float), dsz));

   let n = valueOf(n);
   Bool verbose = True;

   Reg#(Bool) doneReg <- mkReg(False);
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorA <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorB <- mkReg(unpack(0));
   Reg#(MatrixDescriptor#(UInt#(addrwidth))) descriptorC <- mkReg(unpack(0));
   Reg#(UInt#(addrwidth)) dotprodCount <- mkReg(0);

   Vector#(n, PipeOut#(Vector#(N,Float))) aPipes <- mkForkVector(sourceA[0].pipe);

   function Module#(PipeOut#(Float)) mkFxDotProd(Integer i);
      return mkDotProd(aPipes[i], sourceB[i].pipe, descriptorA.numColumns, fromInteger(i));
   endfunction
   Vector#(n, PipeOut#(Float)) fxdotprods <- genWithM(mkFxDotProd);

   FIFOF#(Vector#(N,Float)) dfifo <- mkFIFOF();
   let sinkC <- mkSink(toPipeOut(dfifo));

   XYRangePipeIfc#(UInt#(addrwidth)) xypipeifc <- mkXYRangePipeOut();

   Vector#(TAdd#(n,1), PipeOut#(Tuple2#(UInt#(addrwidth),UInt#(addrwidth)))) xypipes <- mkForkVector(xypipeifc.pipe);

   Reg#(Bool) running <- mkReg(False);
   FIFOF#(Bool) doneFifo <- mkFIFOF();

   Reg#(UInt#(32)) cycles <- mkReg(0);
   rule countCycles;
      cycles <= cycles+1;
   endrule

   for (Integer i = 0; i < n; i = i + 1) begin
      rule startDotProd;
	  Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[i].first;
	  xypipes[i].deq();

	  let row = tpl_1(xy);
	  let col = tpl_2(xy)+fromInteger(i);

	  let startA = row*descriptorA.numColumns; // row major
	  let startB = col*descriptorB.numColumns; // col major layout (pre-transposed)
	  let startC = row*descriptorC.numColumns + col; // row major
	 if (verbose) $display($format(fshow(cycles)+fshow("    startDotProd xy=")+fshow(tuple2(row,col))
				       +fshow(" startA=")+fshow(startA)
				       +fshow(" startB=")+fshow(startB)
				       +fshow(" startC=")+fshow(startC)));

	  if (i == 0) begin
	     sourceA[0].start(descriptorA.pointer, pack(truncate(startA)), pack(truncate(startA + descriptorA.numColumns)));
	     $display($format(fshow(cycles)+fshow("    sourceA[0].start")+fshow(startA)));
	  end
	 sourceB[i].start(descriptorB.pointer, pack(truncate(startB)), pack(truncate(startB + descriptorB.numColumns)));
	 $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].start")+fshow(startB)));
	  if (i == 0)
	     sinkC.vector.start(descriptorC.pointer, pack(truncate(startC)), pack(truncate(startC + fromInteger(n))));
       endrule
       if (i == 0)
	  rule finishSourceA;
	     $display($format(fshow(cycles)+fshow("    sourceA[0].finish ")));
	     let b <- sourceA[0].finish();
	  endrule
      rule finishSourceB;
	 UInt#(TLog#(n)) in = fromInteger(i);
	 $display($format(fshow(cycles)+fshow("    sourceB[")+fshow(in)+fshow("].finish")));
	 let b <- sourceB[i].finish();
      endrule

   end

   rule dotProdValue;
      Tuple2#(UInt#(addrwidth),UInt#(addrwidth)) xy = xypipes[n].first;
      xypipes[n].deq;
      Vector#(N,Float) vs;
      for (Integer i = 0; i < n; i = i + 1) begin
	 let v = fxdotprods[i].first;
	 fxdotprods[i].deq;
	 let xyi = tuple2(tpl_1(xy), tpl_2(xy)+fromInteger(i));
	 if (verbose) $display($format(fshow(cycles)+fshow("    dotprodvalue xy=")+fshow(xyi)+fshow(" dotprod=")+fshow(v)));
	 vs[i] = v;
      end
      dfifo.enq(vs);
   endrule

   rule sinkDone;
      // each time we write a burst of k values via sinkC
      let b <- sinkC.vector.finish();
      let c = dotprodCount-fromInteger(n);
      $display($format(fshow(cycles)+fshow("    sinkDone c")+fshow(c)));
      dotprodCount <= c;
      if (c == 0) begin
	 running <= False;
	 doneFifo.enq(?);
      end
   endrule

   method Action start(ObjectPointer pointerA, UInt#(addrwidth) numRowsA, UInt#(addrwidth) numColumnsA,
		       ObjectPointer pointerB, UInt#(addrwidth) numRowsB, UInt#(addrwidth) numColumnsB,
		       ObjectPointer pointerC) if (dotprodCount == 0);
      XYRangeConfig#(UInt#(addrwidth)) xycfg = XYRangeConfig {xbase: 0, xlimit: numRowsA, xstep: 1,
							      ybase: 0, ylimit: numRowsB, ystep: fromInteger(n) };
      descriptorA <= MatrixDescriptor { pointer: pointerA, base: 0, numRows: numRowsA, numColumns: numColumnsA};
      descriptorB <= MatrixDescriptor { pointer: pointerB, base: 0, numRows: numRowsB, numColumns: numColumnsB};
      descriptorC <= MatrixDescriptor { pointer: pointerC, base: 0, numRows: numRowsA, numColumns: numRowsB};
      dotprodCount <= numRowsA*numRowsB;

      $display("mm pointerA=%d pointerB=%d pointerC=%d\n", pointerA, pointerB, pointerC);
      if (verbose) $display("mm.start ra=%d ca=%d rb=%d cb=%d dotprodCount=%d", numRowsA, numColumnsA, numRowsB, numColumnsB, dotprodCount);
      if (verbose) $display($format(fshow("mm.start ")+fshow(xycfg)));
      xypipeifc.start(xycfg);
   endmethod
   method ActionValue#(Bool) finish();
      $display("mm.finish()");
      doneFifo.deq();
      return True;
   endmethod

   interface ObjectWriteClient dmaClient = sinkC.dmaClient;
endmodule

interface DramMatrixMultiply#(numeric type n, numeric type dmasz);
   interface Vector#(TAdd#(N,1), ObjectReadClient#(dmasz)) readClients;
   interface Vector#(1, ObjectWriteClient#(dmasz)) writeClients;
   method Action start(ObjectPointer pointerA, UInt#(ObjectOffsetSize) numRowsA, UInt#(ObjectOffsetSize) numColumnsA,
		       ObjectPointer pointerB, UInt#(ObjectOffsetSize) numRowsB, UInt#(ObjectOffsetSize) numColumnsB,
		       ObjectPointer pointerC);
   method ActionValue#(Bool) finish();
   method Bit#(32) dbg();
endinterface

(* synthesize *)
module [Module] mkDramMatrixMultiply(DramMatrixMultiply#(N,TMul#(N,32)));
   Vector#(TAdd#(N,1), DmaVectorSource#(DmaSz, Vector#(N,Float))) vfsources <- replicateM(mkDmaVectorSource());
   Vector#(1, VectorSource#(DmaSz, Vector#(N,Float))) xvfsources = cons(vfsources[0].vector, nil);
   Vector#(N, VectorSource#(DmaSz, Vector#(N,Float))) yvfsources = takeAt(1, map(dmaVectorSourceVector, vfsources));
   DmaMatrixMultiplyIfc#(ObjectOffsetSize,DmaSz) dmaMMF <- mkDmaMatrixMultiply(xvfsources, yvfsources, mkDmaVectorSink);
   interface Vector readClients = map(getSourceReadClient, vfsources);
   interface Vector writeClients = cons(dmaMMF.dmaClient, nil);
   method start = dmaMMF.start;
   method finish = dmaMMF.finish;
   method Bit#(32) dbg();
      Bit#(32) d = 0;
      d[0] = pack(vfsources[0].vector.pipe.notEmpty());
      d[1] = pack(vfsources[1].vector.pipe.notEmpty());
      return d;
   endmethod
endmodule

interface Mm#(numeric type n);
   interface MmRequest mmRequest;
   interface TimerRequest timerRequest;
   interface Vector#(TAdd#(1,N), ObjectReadClient#(TMul#(32,N))) readClients;
   interface Vector#(1, ObjectWriteClient#(TMul#(32,n))) writeClients;
endinterface

module [Module] mkMm#(MmIndication ind, TimerIndication timerInd)(Mm#(N))
   provisos (Add#(1,a__,N),
	     Add#(N,0,n),
	     Mul#(N,32,DmaSz)
      );

   let n = valueOf(n);

   DramMatrixMultiply#(N, TMul#(N,32)) dmaMMF <- mkDramMatrixMultiply();

   FIFOF#(Bool) busyFifo <- mkFIFOF();
   rule mmfDone;
      $display("mmfDone");
      let d <- dmaMMF.finish();
      busyFifo.deq();
      ind.mmfDone();
   endrule

   FIFOF#(Bool) timerRunning <- mkFIFOF();
   Reg#(Bit#(64)) cycleCount <- mkReg(0);
   Reg#(Bit#(64)) idleCount <- mkReg(0);
   rule countCycles if (timerRunning.notEmpty());
      cycleCount <= cycleCount + 1;
      if (!busyFifo.notEmpty())
	 idleCount <= idleCount + 1;
   endrule

   interface TimerRequest timerRequest;
         method Action startTimer() if (!timerRunning.notEmpty());
	 cycleCount <= 0;
	 idleCount <= 0;
	 timerRunning.enq(True);
      endmethod
      method Action stopTimer();
	 timerRunning.deq();
	 timerInd.elapsedCycles(cycleCount, idleCount);
      endmethod
   endinterface

   interface MmRequest mmRequest;
      method Action mmf(Bit#(32) h1, Bit#(32) r1, Bit#(32) c1,
			Bit#(32) h2, Bit#(32) r2, Bit#(32) c2,
			Bit#(32) h3);
	 dmaMMF.start(h1, unpack(extend(r1)), unpack(extend(c1)),
		      h2, unpack(extend(r2)), unpack(extend(c2)),
		      h3);
	 busyFifo.enq(True);
      endmethod
   endinterface

   interface Vector readClients = dmaMMF.readClients;
   interface Vector writeClients =  dmaMMF.writeClients;

endmodule


updated non-simulator impl of mkPareff

updated non-simulator impl of mkPareff

// Copyright (c) 2015 Connectal 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.

import Vector::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;

import MemTypes::*;

interface Pareff#(numeric type dataWidth);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(dataWidth)) readresponse();
endinterface

`ifdef BSIM
import "BDPI" function ActionValue#(Bit#(32)) pareff_init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
import "BDPI" function ActionValue#(Bit#(32)) pareff_initfd(Bit#(32) id, Bit#(32) fd);

// implemented in BsimDma.cpp
import "BDPI" function Action write_pareff32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_pareff64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_pareff32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_pareff64(Bit#(32) handle, Bit#(32) addr);

module mkPareff(Pareff#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   FIFO#(Bit#(dataWidth)) dataFifo <- mkFIFO();
      method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
	 let v <- pareff_init(id, handle, size);
	 //return v;
      endmethod
      method Action initfd(Bit#(32) id, Bit#(32) fd);
	 let v <- pareff_initfd(id, fd);
	 //return v;
      endmethod
      method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
	  Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
	  function Action write32(Integer i, Bit#(32) vv);
	     action
		write_pareff32(handle, addr+4*fromInteger(i), vv);
	     endaction
	  endfunction
	  mapM_(uncurry(write32), zip(genVector(), vs));
      endmethod
      method Action  readrequest(Bit#(32) handle, Bit#(32) addr);
	  function ActionValue#(Bit#(32)) read32(Integer i);
	     actionvalue
		let v <- read_pareff32(handle, addr+4*fromInteger(i));
		return v;
	     endactionvalue
	  endfunction
   	  Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(read32, genVector());
	  dataFifo.enq(pack(vs));
      endmethod
      method ActionValue#(Bit#(dataWidth)) readresponse();
          let v <- toGet(dataFifo).get();
	  return v;
      endmethod
endmodule
`endif

`ifdef XSIM
interface XsimMemReadWrite;
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action write32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(32)) readresponse();
endinterface

import "BVI" XsimMemReadWrite =
module mkXsimReadWrite(XsimMemReadWrite);
   method init(init_id, init_handle, init_size) enable (en_init);
   method initfd(initfd_id, initfd_fd) enable (en_initfd);
   method write32(write32_handle, write32_addr, write32_data) enable (en_write32);
   method readrequest(readrequest_handle, readrequest_addr) enable (en_readrequest) ready (rdy_readrequest);
   method readresponse_data readresponse() enable (en_readresponse) ready (rdy_readresponse);
   schedule (init, initfd, write32, readrequest, readresponse) CF (init, initfd, write32, readrequest, readresponse);
endmodule

module mkPareff(Pareff#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   Vector#(TDiv#(dataWidth,32),XsimMemReadWrite) rws <- replicateM(mkXsimReadWrite());
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
      rws[0].init(id, handle, size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
      rws[0].initfd(id, fd);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
      Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
      function Action write32(Integer i, Bit#(32) vv);
	 action
	    rws[i].write32(handle, addr+4*fromInteger(i), vv);
	 endaction
      endfunction
      mapM_(uncurry(write32), zip(genVector(), vs));
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
      function Action doreadrequest(Integer i);
	 action
	    rws[i].readrequest(handle, addr+4*fromInteger(i));
	 endaction
      endfunction
      Vector#(TDiv#(dataWidth,32),Integer) indexes = genVector();
      mapM_(doreadrequest, indexes);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      function ActionValue#(Bit#(32)) readresponse32(Integer i);
	 actionvalue
	    let v <- rws[i].readresponse();
	    return v;
	 endactionvalue
      endfunction
      Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(readresponse32, genVector());
      return pack(vs);
   endmethod
endmodule
`endif

`ifndef BSIM
`ifndef XSIM
module mkPareff(Pareff#(dataWidth) ifc);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      return 0;
   endmethod
endmodule
`endif
`endif

module mkPareffDmaMaster(PhysMemSlave#(serverAddrWidth,serverBusWidth))
   provisos(Div#(serverBusWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,serverBusWidth),
	    Log#(dataWidthBytes,beatShift),
	    Mul#(TDiv#(serverBusWidth, 32), 32, serverBusWidth),
	    Bits#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)), a__)
	    );

   let verbose = False;
   Pareff#(serverBusWidth) rw <- mkPareff();

   Reg#(Bit#(BurstLenSize))  readLenReg <- mkReg(0);
   Reg#(Bit#(32))         readOffsetReg <- mkReg(0);

   Reg#(Bit#(BurstLenSize))  writeLenReg <- mkReg(0);
   Reg#(Bit#(32))         writeOffsetReg <- mkReg(0);

   let readLatency_I = 150;
   let writeLatency_I = 150;

   Bit#(64) readLatency = fromInteger(readLatency_I);
   Bit#(64) writeLatency = fromInteger(writeLatency_I);

   Reg#(Bit#(64)) req_ar_b_ts <- mkReg(0);
   Reg#(Bit#(64)) req_aw_b_ts <- mkReg(0);
   Reg#(Bit#(64)) cycles <- mkReg(0);
   Reg#(Bit#(64)) last_reqAr <- mkReg(0);
   Reg#(Bit#(64)) last_read_eob <- mkReg(0);
   Reg#(Bit#(64)) last_write_eob <- mkReg(0);

   FIFOF#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)))  readDelayFifo <- mkSizedFIFOF(readLatency_I);
   FIFOF#(Tuple2#(Bit#(64),PhysMemRequest#(serverAddrWidth))) writeDelayFifo <- mkSizedFIFOF(writeLatency_I);

   FIFOF#(Tuple2#(Bit#(64), Bit#(MemTagSize))) bFifo <- mkSizedFIFOF(writeLatency_I);
   FIFOF#(Tuple2#(Bit#(MemTagSize),Bool)) taglastfifo <- mkFIFOF();
   rule increment_cycle;
      cycles <= cycles+1;
   endrule

   let read_jitter = True; //cycles[4:0] == 0;
   let write_jitter = True; //cycles[4:0] == 5;

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Bit#(8)) reqs <- mkSizedFIFO(32);

   let beat_shift = fromInteger(valueOf(beatShift));

   rule read_rule if (readDelayFifo.notEmpty() && (cycles-tpl_1(readDelayFifo.first) > readLatency));
	 match { .reqTime, .req } = readDelayFifo.first;
	 Bit#(BurstLenSize) readLen = readLenReg;
	 Bit#(32) readOffset = readOffsetReg;
	 Bit#(MemTagSize) tag = req.tag;
	 Bit#(8) handle = req.addr[39:32];

	 if (readLen == 0) begin
	    req_ar_b_ts <= cycles;
	    readLen     = req.burstLen>>beat_shift;
	    readOffset  = 0;
	 end
	 rw.readrequest(extend(handle), req.addr[31:0]+readOffset);
	 let last = (readLen == 1);
	 if (last)
	    readDelayFifo.deq();
	 taglastfifo.enq(tuple2(tag, last));
	 readLenReg <= readLen - 1;
	 readOffsetReg <= readOffset + fromInteger(valueOf(serverBusWidth)/8);
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
            if (verbose) $display("%d axiSlave.read.readAddr %h bc %d", cycles, req.addr, req.burstLen);
	    //readAddrGenerator.request.put(req);
	    readDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(serverBusWidth)) get();
	     match { .tag, .last } <- toGet(taglastfifo).get();
 	     let v <- rw.readresponse();
	     return MemData { data: v, tag: tag, last: last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
	 //$display("mkBsimHost::req_aw id=%d", req.tag);
	 writeDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Put writeData;
	 method Action put(MemData#(serverBusWidth) resp) if (writeDelayFifo.notEmpty && (cycles-tpl_1(writeDelayFifo.first)) > writeLatency);
	    match { .reqTime, .req } = writeDelayFifo.first;
	    Bit#(BurstLenSize) writeLen = writeLenReg;
	    Bit#(32) writeOffset = writeOffsetReg;
	    Bit#(MemTagSize) tag = req.tag;
	    Bit#(8) handle = req.addr[39:32];
	    if (writeLenReg == 0) begin
	       req_aw_b_ts <= cycles;
	       writeLen = req.burstLen>>beat_shift;
	       writeOffset = 0;
	    end
	    rw.write(extend(handle), req.addr[31:0] + writeOffset, resp.data);
	    writeLenReg <= writeLen - 1;
	    writeOffsetReg <= writeOffset + fromInteger(valueOf(serverBusWidth)/8);
	    if (writeLen == 1) begin
	       bFifo.enq(tuple2(cycles,tag));
	       writeDelayFifo.deq;
	    end
	 endmethod
      endinterface
      interface Get writeDone;
	 method ActionValue#(Bit#(MemTagSize)) get() if ((cycles-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
	 endmethod
      endinterface
   endinterface
endmodule

// Copyright (c) 2015 Connectal 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.

import Vector::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;

import MemTypes::*;

interface Pareff#(numeric type dataWidth);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(dataWidth)) readresponse();
endinterface

`ifdef BSIM
import "BDPI" function ActionValue#(Bit#(32)) pareff_init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
import "BDPI" function ActionValue#(Bit#(32)) pareff_initfd(Bit#(32) id, Bit#(32) fd);

// implemented in BsimDma.cpp
import "BDPI" function Action write_pareff32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_pareff64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_pareff32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_pareff64(Bit#(32) handle, Bit#(32) addr);

module mkPareff(Pareff#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   FIFO#(Bit#(dataWidth)) dataFifo <- mkFIFO();
      method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
	 let v <- pareff_init(id, handle, size);
	 //return v;
      endmethod
      method Action initfd(Bit#(32) id, Bit#(32) fd);
	 let v <- pareff_initfd(id, fd);
	 //return v;
      endmethod
      method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
	  Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
	  function Action write32(Integer i, Bit#(32) vv);
	     action
		write_pareff32(handle, addr+4*fromInteger(i), vv);
	     endaction
	  endfunction
	  mapM_(uncurry(write32), zip(genVector(), vs));
      endmethod
      method Action  readrequest(Bit#(32) handle, Bit#(32) addr);
	  function ActionValue#(Bit#(32)) read32(Integer i);
	     actionvalue
		let v <- read_pareff32(handle, addr+4*fromInteger(i));
		return v;
	     endactionvalue
	  endfunction
   	  Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(read32, genVector());
	  dataFifo.enq(pack(vs));
      endmethod
      method ActionValue#(Bit#(dataWidth)) readresponse();
          let v <- toGet(dataFifo).get();
	  return v;
      endmethod
endmodule
`endif

`ifdef XSIM
interface XsimMemReadWrite;
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action write32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(32)) readresponse();
endinterface

import "BVI" XsimMemReadWrite =
module mkXsimReadWrite(XsimMemReadWrite);
   method init(init_id, init_handle, init_size) enable (en_init);
   method initfd(initfd_id, initfd_fd) enable (en_initfd);
   method write32(write32_handle, write32_addr, write32_data) enable (en_write32);
   method readrequest(readrequest_handle, readrequest_addr) enable (en_readrequest) ready (rdy_readrequest);
   method readresponse_data readresponse() enable (en_readresponse) ready (rdy_readresponse);
   schedule (init, initfd, write32, readrequest, readresponse) CF (init, initfd, write32, readrequest, readresponse);
endmodule

module mkPareff(Pareff#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   Vector#(TDiv#(dataWidth,32),XsimMemReadWrite) rws <- replicateM(mkXsimReadWrite());
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
      rws[0].init(id, handle, size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
      rws[0].initfd(id, fd);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
      Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
      function Action write32(Integer i, Bit#(32) vv);
	 action
	    rws[i].write32(handle, addr+4*fromInteger(i), vv);
	 endaction
      endfunction
      mapM_(uncurry(write32), zip(genVector(), vs));
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
      function Action doreadrequest(Integer i);
	 action
	    rws[i].readrequest(handle, addr+4*fromInteger(i));
	 endaction
      endfunction
      Vector#(TDiv#(dataWidth,32),Integer) indexes = genVector();
      mapM_(doreadrequest, indexes);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      function ActionValue#(Bit#(32)) readresponse32(Integer i);
	 actionvalue
	    let v <- rws[i].readresponse();
	    return v;
	 endactionvalue
      endfunction
      Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(readresponse32, genVector());
      return pack(vs);
   endmethod
endmodule
`endif

`ifndef BSIM
`ifndef XSIM
module mkPareff(Pareff#(dataWidth) ifc);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   endmethod
   method ActionValue#(Bit#(dataWidth)) read(Bit#(32) handle, Bit#(32) addr);
      return 0;
   endmethod
endmodule
`endif
`endif

module mkPareffDmaMaster(PhysMemSlave#(serverAddrWidth,serverBusWidth))
   provisos(Div#(serverBusWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,serverBusWidth),
	    Log#(dataWidthBytes,beatShift),
	    Mul#(TDiv#(serverBusWidth, 32), 32, serverBusWidth),
	    Bits#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)), a__)
	    );

   let verbose = False;
   Pareff#(serverBusWidth) rw <- mkPareff();

   Reg#(Bit#(BurstLenSize))  readLenReg <- mkReg(0);
   Reg#(Bit#(32))         readOffsetReg <- mkReg(0);

   Reg#(Bit#(BurstLenSize))  writeLenReg <- mkReg(0);
   Reg#(Bit#(32))         writeOffsetReg <- mkReg(0);

   let readLatency_I = 150;
   let writeLatency_I = 150;

   Bit#(64) readLatency = fromInteger(readLatency_I);
   Bit#(64) writeLatency = fromInteger(writeLatency_I);

   Reg#(Bit#(64)) req_ar_b_ts <- mkReg(0);
   Reg#(Bit#(64)) req_aw_b_ts <- mkReg(0);
   Reg#(Bit#(64)) cycles <- mkReg(0);
   Reg#(Bit#(64)) last_reqAr <- mkReg(0);
   Reg#(Bit#(64)) last_read_eob <- mkReg(0);
   Reg#(Bit#(64)) last_write_eob <- mkReg(0);

   FIFOF#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)))  readDelayFifo <- mkSizedFIFOF(readLatency_I);
   FIFOF#(Tuple2#(Bit#(64),PhysMemRequest#(serverAddrWidth))) writeDelayFifo <- mkSizedFIFOF(writeLatency_I);

   FIFOF#(Tuple2#(Bit#(64), Bit#(MemTagSize))) bFifo <- mkSizedFIFOF(writeLatency_I);
   FIFOF#(Tuple2#(Bit#(MemTagSize),Bool)) taglastfifo <- mkFIFOF();
   rule increment_cycle;
      cycles <= cycles+1;
   endrule

   let read_jitter = True; //cycles[4:0] == 0;
   let write_jitter = True; //cycles[4:0] == 5;

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Bit#(8)) reqs <- mkSizedFIFO(32);

   let beat_shift = fromInteger(valueOf(beatShift));

   rule read_rule if (readDelayFifo.notEmpty() && (cycles-tpl_1(readDelayFifo.first) > readLatency));
	 match { .reqTime, .req } = readDelayFifo.first;
	 Bit#(BurstLenSize) readLen = readLenReg;
	 Bit#(32) readOffset = readOffsetReg;
	 Bit#(MemTagSize) tag = req.tag;
	 Bit#(8) handle = req.addr[39:32];

	 if (readLen == 0) begin
	    req_ar_b_ts <= cycles;
	    readLen     = req.burstLen>>beat_shift;
	    readOffset  = 0;
	 end
	 rw.readrequest(extend(handle), req.addr[31:0]+readOffset);
	 let last = (readLen == 1);
	 if (last)
	    readDelayFifo.deq();
	 taglastfifo.enq(tuple2(tag, last));
	 readLenReg <= readLen - 1;
	 readOffsetReg <= readOffset + fromInteger(valueOf(serverBusWidth)/8);
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
            if (verbose) $display("%d axiSlave.read.readAddr %h bc %d", cycles, req.addr, req.burstLen);
	    //readAddrGenerator.request.put(req);
	    readDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(serverBusWidth)) get();
	     match { .tag, .last } <- toGet(taglastfifo).get();
 	     let v <- rw.readresponse();
	     return MemData { data: v, tag: tag, last: last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
	 //$display("mkBsimHost::req_aw id=%d", req.tag);
	 writeDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Put writeData;
	 method Action put(MemData#(serverBusWidth) resp) if (writeDelayFifo.notEmpty && (cycles-tpl_1(writeDelayFifo.first)) > writeLatency);
	    match { .reqTime, .req } = writeDelayFifo.first;
	    Bit#(BurstLenSize) writeLen = writeLenReg;
	    Bit#(32) writeOffset = writeOffsetReg;
	    Bit#(MemTagSize) tag = req.tag;
	    Bit#(8) handle = req.addr[39:32];
	    if (writeLenReg == 0) begin
	       req_aw_b_ts <= cycles;
	       writeLen = req.burstLen>>beat_shift;
	       writeOffset = 0;
	    end
	    rw.write(extend(handle), req.addr[31:0] + writeOffset, resp.data);
	    writeLenReg <= writeLen - 1;
	    writeOffsetReg <= writeOffset + fromInteger(valueOf(serverBusWidth)/8);
	    if (writeLen == 1) begin
	       bFifo.enq(tuple2(cycles,tag));
	       writeDelayFifo.deq;
	    end
	 endmethod
      endinterface
      interface Get writeDone;
	 method ActionValue#(Bit#(MemTagSize)) get() if ((cycles-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
	 endmethod
      endinterface
   endinterface
endmodule


use spiroot and spitap

use spiroot and spitap

// 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 FIFO::*;
import SpiTap::*;

interface SerialconfigIndication;
   method Action ack(Bit#(32) a, Bit#(32) d);
endinterface

interface SerialconfigRequest;
   method Action send(Bit#(32) a, Bit#(32) d);
endinterface

module mkSerialconfigRequest#(SerialconfigIndication indication)(SerialconfigRequest);

   SpiTap tap1 <- mkSpiTap('hdeadbeef);
//   SpiTap tap2 <- mkSpiTap('hfeedface);
   FIFO#(SpiItem) spi <- mkSpiRoot(tap1);

   rule getresults;
      indication.ack(spi.first());
      spi.deq();
   endrule

   method Action send(Bit#(32) a, Bit#(32) d);
      spi.enq(Item{a: a, d: d});
   endmethod

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 JtagTap::*;

interface SerialconfigIndication;
   method Action sendack(bit tms, bit tdi);
   method Action recvack(bit tdo);
   method Action stateack(TapState s1, TapState s2);
endinterface

interface SerialconfigRequest;
   method Action write(bit tms, bit tdi);
   method Action read();
   method Action getstate();
endinterface

module mkSerialconfigRequest#(SerialconfigIndication indication)(SerialconfigRequest);

   JtagTap tap1 <- mkJtagTap('hdeadbeef);
   JtagTap tap2 <- mkJtagTap('hfeedface);

   method Action read();
      indicaton.recv(tap2.tdo);
   endmethod

   method Action write(bit tms, bit tdi);
      tap1.tms(tms);
      tap2.tms(tms);
      tap1.tdi(tdi);
      tap2.tdi(tap1.tdo);
      indication.sendack(tms, tdi);
   endmethod

   method Action getstate();
      indication.stateack(tap1.getstate, tap2.getstate);
   endmethod

endmodule