fixed some(not all) warnings on lwrite_cnt and lread_cnt.

// Copyright (c) 2015 Cornell University.

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

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

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

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

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

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

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

interface SonicUserIndication;
   method Action dtp_read_version_resp(Bit#(32) version);
   method Action dtp_read_delay_resp(Bit#(8) port_no, Bit#(32) delay);
   method Action dtp_read_state_resp(Bit#(8) port_no, Bit#(32) state);
   method Action dtp_read_error_resp(Bit#(8) port_no, Bit#(64) jumpc);
   method Action dtp_read_cnt_resp(Bit#(64) val);
   method Action dtp_logger_read_cnt_resp(Bit#(8) port_no, Bit#(64) localc, Bit#(64) msg1, Bit#(64) msg2);
   method Action dtp_read_local_cnt_resp(Bit#(8) port_no, Bit#(64) val);
   method Action dtp_read_global_cnt_resp(Bit#(64) val);
   method Action dtp_read_beacon_interval_resp(Bit#(8) port_no, Bit#(32) interval);
   method Action dtp_debug_rcvd_msg_resp(Bit#(8) port_no, Bit#(32) lread_cnt_enq1, Bit#(32) lread_cnt_enq2, Bit#(32) lread_cnt_deq);
   method Action dtp_debug_sent_msg_resp(Bit#(8) port_no, Bit#(32) lwrite_cnt_enq, Bit#(32) lwrite_cnt_deq1, Bit#(32) lwrite_cnt_deq2);
   method Action dtp_debug_rcvd_err_resp(Bit#(8) port_no, Bit#(32) err_cnt);
endinterface

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

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

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

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

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

   Reg#(Bit#(8))  lwrite_port <- mkReg(0);
   FIFOF#(BufData) lwrite_data_cycle1 <- mkSizedBypassFIFOF(3);
   FIFOF#(BufData) lwrite_data_cycle2 <- mkSizedBypassFIFOF(3);
   FIFOF#(void) log_write_cf <- mkFIFOF;
   Vector#(4, Reg#(Bit#(32))) lwrite_cnt_enq <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32))) lwrite_cnt_deq1 <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32))) lwrite_cnt_deq2 <- replicateM(mkReg(0));

   Vector#(4, FIFOF#(BufData)) lread_data_cycle1 <- replicateM(mkSizedBypassFIFOF(4));
   Vector#(4, FIFOF#(BufData)) lread_data_cycle2 <- replicateM(mkSizedBypassFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) lread_data_timestamp <- replicateM(mkSizedBypassFIFOF(4));
   Vector#(4, Reg#(Bit#(32)))  lread_cnt_enq1 <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32)))  lread_cnt_enq2 <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32)))  lread_cnt_deq <- replicateM(mkReg(0));

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

   rule count;
      cycle_count <= cycle_count + 1;
   endrule

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

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

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

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

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

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

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

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

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

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

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

   for (Integer i=0; i<4; i=i+1) begin
      rule save_host_data (!dtpResetOut.isAsserted);
         let v <- toGet(toHostFifo[i]).get;
         if (v[52] == 0) begin
            lread_data_cycle1[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
            lread_cnt_enq1[i] <= lread_cnt_enq1[i] + 1;
         end
         else if (v[52] == 1) begin
            lread_data_cycle2[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
            Bit#(53) timestamp = 0;
            if (isSwitch_reg == 0) begin // 0 for NIC, 1 for Switch
               timestamp = clocal_reg[i];
            end
            else begin
               timestamp = cglobal_reg;
            end
            lread_data_timestamp[i].enq(timestamp);
            lread_cnt_enq2[i] <= lread_cnt_enq2[i] + 1;
         end
      endrule
      rule reset_host_data (dtpResetOut.isAsserted);
         lread_cnt_enq1[i] <= 0;
         lread_cnt_enq2[i] <= 0;
      endrule
   end

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

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

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

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

// Copyright (c) 2015 Cornell University.

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

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

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

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

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

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

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

interface SonicUserIndication;
   method Action dtp_read_version_resp(Bit#(32) version);
   method Action dtp_read_delay_resp(Bit#(8) port_no, Bit#(32) delay);
   method Action dtp_read_state_resp(Bit#(8) port_no, Bit#(32) state);
   method Action dtp_read_error_resp(Bit#(8) port_no, Bit#(64) jumpc);
   method Action dtp_read_cnt_resp(Bit#(64) val);
   method Action dtp_logger_read_cnt_resp(Bit#(8) port_no, Bit#(64) localc, Bit#(64) msg1, Bit#(64) msg2);
   method Action dtp_read_local_cnt_resp(Bit#(8) port_no, Bit#(64) val);
   method Action dtp_read_global_cnt_resp(Bit#(64) val);
   method Action dtp_read_beacon_interval_resp(Bit#(8) port_no, Bit#(32) interval);
   method Action dtp_debug_rcvd_msg_resp(Bit#(8) port_no, Bit#(32) lread_cnt_enq1, Bit#(32) lread_cnt_enq2, Bit#(32) lread_cnt_deq);
   method Action dtp_debug_sent_msg_resp(Bit#(8) port_no, Bit#(32) lwrite_cnt_enq, Bit#(32) lwrite_cnt_deq1, Bit#(32) lwrite_cnt_deq2);
   method Action dtp_debug_rcvd_err_resp(Bit#(8) port_no, Bit#(32) err_cnt);
endinterface

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

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

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

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

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

   Reg#(Bit#(8))  lwrite_port <- mkReg(0);
   FIFOF#(BufData) lwrite_data_cycle1 <- mkSizedBypassFIFOF(3);
   FIFOF#(BufData) lwrite_data_cycle2 <- mkSizedBypassFIFOF(3);
   FIFOF#(void) log_write_cf <- mkFIFOF;
   Vector#(4, Reg#(Bit#(32))) lwrite_cnt_enq <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32))) lwrite_cnt_deq1 <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32))) lwrite_cnt_deq2 <- replicateM(mkReg(0));

   Vector#(4, FIFOF#(BufData)) lread_data_cycle1 <- replicateM(mkSizedBypassFIFOF(4));
   Vector#(4, FIFOF#(BufData)) lread_data_cycle2 <- replicateM(mkSizedBypassFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) lread_data_timestamp <- replicateM(mkSizedBypassFIFOF(4));
   Vector#(4, Reg#(Bit#(32)))  lread_cnt_enq1 <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32)))  lread_cnt_enq2 <- replicateM(mkReg(0));
   Vector#(4, Reg#(Bit#(32)))  lread_cnt_deq <- replicateM(mkReg(0));

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

   rule count;
      cycle_count <= cycle_count + 1;
   endrule

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


changed axi id len 12 -> 6

changed axi id len 12 -> 6

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


a little cleanup

a little cleanup

Change-Id: I87220329f8c62b27631667de165ec295bc5a2555

import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import FIFOF::*;
import Connectable::*;
import ClientServer::*;
import Memory::*;
import BRAM::*;
import DefaultValue::*;
import FloatingPoint::*;
import Real::*;
import BRAM::*;
import Dma::*;
import DmaVector::*;
import Pipe::*;
import FloatOps::*;

interface SigmoidTable#(numeric type tsz);
   interface Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) ports;
   interface ReadOnly#(Float) rscale;
   interface ReadOnly#(Float) llimit;
   interface ReadOnly#(Float) ulimit;
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
   method Bit#(32) tableSize();
endinterface

module mkSigmoidTable(SigmoidTable#(tsz));
   let tsz = valueOf(tsz);
   BRAM_Configure bramCfg = defaultValue;
   let memorySize = 2**tsz;
   bramCfg.memorySize = memorySize;
   BRAM2Port#(Bit#(tsz), Vector#(3, Float)) sigmoidTable <- mkBRAM2Server(bramCfg);

   Reg#(Float) rscaleReg <- mkReg(fromReal(0.0));
   Reg#(Float) llimitReg <- mkReg(fromReal(0.0));
   Reg#(Float) ulimitReg <- mkReg(fromReal(0.0));

   Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) bramPorts;
   bramPorts[0] = sigmoidTable.portA;
   bramPorts[1] = sigmoidTable.portB;

   interface ReadOnly rscale = regToReadOnly(rscaleReg);
   interface ReadOnly llimit = regToReadOnly(llimitReg);
   interface ReadOnly ulimit = regToReadOnly(ulimitReg);
   interface Vector ports = bramPorts;
   method Action setSigmoidLimits(Float _rscale, Float _llimit, Float _ulimit);
      $display("setSigmoidLimits memorySize=%d\n", memorySize);
      rscaleReg <= _rscale;
      llimitReg <= _llimit;
      ulimitReg <= _ulimit;
      $display($format("rscale=", fshow(_rscale), "pack(rscale)=", fshow(pack(_rscale)), " llimit=", fshow(_llimit), " ulimit=", fshow(_ulimit)));
   endmethod
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
      sigmoidTable.portB.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: addr, datain: v});
   endmethod
   method Bit#(32) tableSize();
      return (1 << tsz);
   endmethod
endmodule

module mkSigmoidServer#(SigmoidTable#(tsz) sigmoidTable)(Server#(Float,Float))
   provisos (Add#(tsz,2,usz),
	     Add#(a__, usz, 32)
	     );
   let tsz = valueOf(tsz);
   Int#(usz) numEntries = 1<<fromInteger(tsz);
   // linear approximation around in range [-8,8]

   Bool verbose = False;
   FIFOF#(Float) angleFifo2 <- mkFIFOF();
   FIFOF#(Float) angleFifo <- mkFIFOF();
   let multiplier <- mkFloatMultiplier();
   let adder <- mkFloatAdder();
   let mac <- mkFloatMac();

   rule lookupEntry;
      Float angle = 0;
      if (verbose) begin
	 angle = angleFifo2.first;
	 angleFifo2.deq();
      end
      let response <- multiplier.response.get();
      Float scaled_angle = tpl_1(response);
      Exception e = tpl_2(response);
      if (pack(e) != 0) $display("lookup.exception e=%h scaled_angle=%h", e, pack(scaled_angle));

      Int#(usz) i = truncate(toInt32(scaled_angle));
      Bit#(tsz) index = truncate(pack(i + numEntries/2));
      if (i > (numEntries/2-1))
	 index = truncate(pack(numEntries-1));
      if (i < -numEntries/2)
	 index = 0;
      if (verbose)
	 $display("sigmoid lookupEntry angle=%h i=%d index=%d numEntries=%d", pack(angle), i, index, numEntries);
      sigmoidTable.ports[0].request.put(BRAMRequest{ write: False, responseOnWrite: False, address: index, datain: ?});
   endrule

   FIFOF#(Vector#(3, Float)) vFifo <- mkFIFOF();
   rule computeDelta;
      let vs <- sigmoidTable.ports[0].response.get();
      let angle = angleFifo.first();
      angleFifo.deq();
      if (verbose) $display("computeDelta angle=%h vs[0]=%h", pack(angle), pack(vs[0]));
      adder.request.put(tuple3(angle, vs[0], defaultValue));
      vFifo.enq(vs);
   endrule

   rule interpolate;
      let vs = vFifo.first();
      vFifo.deq();
      let result <- adder.response.get();
      let delta = tpl_1(result);
      Exception e = tpl_2(result);
      if (pack(e) != 0) $display("interpolate.exception e=%h delta=%h", e, pack(delta));
      if (verbose) $display("sigmoid interpolate delta=%h vs[1]=%h vs[2]", pack(delta), pack(vs[1]), pack(vs[2]));
      mac.request.put(tuple4(tagged Valid vs[1], vs[2], delta, defaultValue));
   endrule

   interface Put request;
      method Action put(Float angle);
	 let c = compareFP(angle, sigmoidTable.llimit);
	 let d = compareFP(angle, sigmoidTable.ulimit);
	 if (c == LT)
	    angle = sigmoidTable.llimit;
	 if (d == GT)
	    angle = sigmoidTable.ulimit;
	 if (verbose)
	    angleFifo2.enq(angle);
	 angleFifo.enq(angle);
	 multiplier.request.put(tuple3(angle, sigmoidTable.rscale, defaultValue));
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Float) get();
	 let result <- mac.response.get();
	 let v = tpl_1(result);
	 Exception e = tpl_2(result);
	 if (pack(e) != 0) $display("mac.exception e=%h v=%h", e, pack(v));
	return v;
     endmethod
   endinterface
endmodule

module [Module] mkSigmoid#(SigmoidTable#(tsz) sigmoidTable, PipeOut#(Float) in)(PipeOut#(Float))
   provisos (Add#(a__, TAdd#(tsz, 2), 32));

   let server <- mkSigmoidServer(sigmoidTable);

   FIFOF#(Float) rfifo <- mkFIFOF;
   rule sigmoidOut;
      let sv <- server.response.get();
      rfifo.enq(sv);
   endrule
   mkConnection(in, server.request);
   return toPipeOut(rfifo);
endmodule

interface DmaSigmoidIfc#(numeric type dsz);
   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numElts);
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
   method Bit#(32) tableSize();
   interface ObjectWriteClient#(dsz) dmaClient;
   interface PipeOut#(Bool) pipe;
   interface PipeOut#(Bool) sigmoidTablePipe;
endinterface

module [Module] mkDmaSigmoid#(VectorSource#(dmasz, Vector#(n,Float)) source,
			      VectorSource#(dmasz, Vector#(n,Float)) tableSource,
			      function Module#(DmaVectorSink#(dsz, Vector#(n, Float))) mkSink(PipeOut#(Vector#(n, Float)) pipe_in)
   )
   (DmaSigmoidIfc#(dsz))
   provisos (Bits#(Float, fsz)
	     , Mul#(fsz,n,dmasz)
	     , Add#(1, a__, n)
	     , Add#(b__, n, 4)
	     , Mul#(n, c__, 4)
      );

   Bool verbose = False;

   Vector#(n, SigmoidTable#(6)) sigmoidTables <- replicateM(mkSigmoidTable);
   Vector#(n, Server#(Float,Float)) sigmoidServers;
   for (Integer i = 0; i < valueOf(n); i = i + 1) begin
      let s <- mkSigmoidServer(sigmoidTables[i]);
      sigmoidServers[i] = s;
   end

   Reg#(Bool) updatingSigmoidTable <- mkReg(False);
   Reg#(Bit#(6)) entryNumber <- mkReg(0);

   FIFOF#(Bool) sigmoidUpdatedFifo <- mkFIFOF();

   PipeOut#(Vector#(4, Float)) sigmoidSourceFunnel <- mkUnfunnel(tableSource.pipe);
   rule updateSigmoidTableRule if (updatingSigmoidTable);
      let vs = sigmoidSourceFunnel.first;
      if (verbose) $display("updateSigmaTableRule vs[0]=%h entryNumber=%d", vs[0], entryNumber);
      sigmoidSourceFunnel.deq();
      Vector#(3,Float) vs3 = take(vs);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].updateSigmoidTable(entryNumber, vs3);
      end
      entryNumber <= entryNumber + 1;
   endrule

   Reg#(Bit#(32)) countInput <- mkReg(0);
   rule consumeInput if (!updatingSigmoidTable);
      let vs = source.pipe.first;
      source.pipe.deq();
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         sigmoidServers[i].request.put(vs[i]);
      end
      if (verbose) $display("consumeInput countInput=%d vs[0]=%h", countInput+1, vs[0]);
      countInput <= countInput + 1;
   endrule

   Reg#(Bit#(32)) count <- mkReg(0);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule enqResult;
      Vector#(n, Float) vs;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         let v <- sigmoidServers[i].response.get();
	 vs[i] = v;
      end
      if (verbose) $display("sigmoid count=%d value=%h", count+1, vs);
      count <= count + 1;
      dfifo.enq(vs);
   endrule

   let sinkC <- mkSink(toPipeOut(dfifo));

   rule tableSourceFinishRule;
      if (verbose) $display("tableSource.finish()");
      let b <- tableSource.finish();
      updatingSigmoidTable <= False;
      sigmoidUpdatedFifo.enq(True);
   endrule
   rule sourceFinishRule;
      let b <- source.finish();
      if (verbose) $display("sigmoid.source.finish()");
   endrule

   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numvalues);
      source.start(pointerA, 0, pack(numvalues));
      sinkC.vector.start(pointerB, 0, pack(numvalues));
      if (verbose) $display("sigmoid.start numvalues=%d", numvalues);
   endmethod
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].setSigmoidLimits(rscale, llimit, ulimit);
      end
   endmethod
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numvalues);
      entryNumber <= 0;
      updatingSigmoidTable <= True;
      tableSource.start(readPointer, extend(readOffset), 4*extend(numvalues));
   endmethod
   method Bit#(32) tableSize();
      return sigmoidTables[0].tableSize();
   endmethod

   interface ObjectWriteClient dmaClient = sinkC.dmaClient;
   interface PipeOut pipe = sinkC.vector.pipe;
   interface PipeOut sigmoidTablePipe = toPipeOut(sigmoidUpdatedFifo);

endmodule

import RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import FIFOF::*;
import Connectable::*;
import ClientServer::*;
import Memory::*;
import BRAM::*;
import DefaultValue::*;
import FloatingPoint::*;
import Real::*;
import BRAM::*;
import Dma::*;
import DmaVector::*;
import Pipe::*;
import FloatOps::*;

interface SigmoidTable#(numeric type tsz);
   interface Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) ports;
   interface ReadOnly#(Float) rscale;
   interface ReadOnly#(Float) llimit;
   interface ReadOnly#(Float) ulimit;
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
   method Bit#(32) tableSize();
endinterface

module mkSigmoidTable(SigmoidTable#(tsz));
   let tsz = valueOf(tsz);
   BRAM_Configure bramCfg = defaultValue;
   let memorySize = 2**tsz;
   bramCfg.memorySize = memorySize;
   BRAM2Port#(Bit#(tsz), Vector#(3, Float)) sigmoidTable <- mkBRAM2Server(bramCfg);

   Reg#(Float) rscaleReg <- mkReg(fromReal(0.0));
   Reg#(Float) llimitReg <- mkReg(fromReal(0.0));
   Reg#(Float) ulimitReg <- mkReg(fromReal(0.0));

   Vector#(2, BRAMServer#(Bit#(tsz), Vector#(3,Float))) bramPorts;
   bramPorts[0] = sigmoidTable.portA;
   bramPorts[1] = sigmoidTable.portB;

   interface ReadOnly rscale = regToReadOnly(rscaleReg);
   interface ReadOnly llimit = regToReadOnly(llimitReg);
   interface ReadOnly ulimit = regToReadOnly(ulimitReg);
   interface Vector ports = bramPorts;
   method Action setSigmoidLimits(Float _rscale, Float _llimit, Float _ulimit);
      $display("memorySize=%d\n", memorySize);
      rscaleReg <= _rscale;
      llimitReg <= _llimit;
      ulimitReg <= _ulimit;
      $display($format("rscale=", fshow(_rscale), "pack(rscale)=", fshow(pack(_rscale)), " llimit=", fshow(_llimit), " ulimit=", fshow(_ulimit)));
   endmethod
   method Action updateSigmoidTable(Bit#(tsz) addr, Vector#(3,Float) v);
      sigmoidTable.portB.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: addr, datain: v});
   endmethod
   method Bit#(32) tableSize();
      return (1 << tsz);
   endmethod
endmodule

module mkSigmoidServer#(SigmoidTable#(tsz) sigmoidTable)(Server#(Float,Float))
   provisos (Add#(tsz,2,usz),
	     Add#(a__, usz, 32)
	     );
   let tsz = valueOf(tsz);
   Int#(usz) numEntries = 1<<fromInteger(tsz);
   // linear approximation around in range [-8,8]

   Bool verbose = True;
   FIFOF#(Float) angleFifo2 <- mkFIFOF();
   FIFOF#(Float) angleFifo <- mkFIFOF();
   let multiplier <- mkFloatMultiplier();
   let adder <- mkFloatAdder();
   let mac <- mkFloatMac();

   rule lookupEntry;
      Float angle = 0;
      if (verbose) begin
	 angle = angleFifo2.first;
	 angleFifo2.deq();
      end
      let response <- multiplier.response.get();
      Float scaled_angle = tpl_1(response);
      Exception e = tpl_2(response);
      if (pack(e) != 0) $display("lookup.exception e=%h scaled_angle=%h", e, pack(scaled_angle));

      Int#(usz) i = truncate(toInt32(scaled_angle));
      Bit#(tsz) index = truncate(pack(i + numEntries/2));
      if (i > (numEntries/2-1))
	 index = truncate(pack(numEntries-1));
      if (i < -numEntries/2)
	 index = 0;
      if (verbose)
	 $display("sigmoid lookupEntry angle=%h i=%d index=%d numEntries=%d", pack(angle), i, index, numEntries);
      sigmoidTable.ports[0].request.put(BRAMRequest{ write: False, responseOnWrite: False, address: index, datain: ?});
   endrule

   FIFOF#(Vector#(3, Float)) vFifo <- mkFIFOF();
   rule computeDelta;
      let vs <- sigmoidTable.ports[0].response.get();
      let angle = angleFifo.first();
      angleFifo.deq();
      if (verbose) $display("computeDelta angle=%h vs[0]=%h", pack(angle), pack(vs[0]));
      adder.request.put(tuple3(angle, vs[0], defaultValue));
      vFifo.enq(vs);
   endrule

   rule interpolate;
      let vs = vFifo.first();
      vFifo.deq();
      let result <- adder.response.get();
      let delta = tpl_1(result);
      Exception e = tpl_2(result);
      if (pack(e) != 0) $display("interpolate.exception e=%h delta=%h", e, pack(delta));
      if (verbose) $display("sigmoid interpolate delta=%h vs[1]=%h vs[2]", pack(delta), pack(vs[1]), pack(vs[2]));
      mac.request.put(tuple4(tagged Valid vs[1], vs[2], delta, defaultValue));
   endrule

   interface Put request;
      method Action put(Float angle);
	 let c = compareFP(angle, sigmoidTable.llimit);
	 let d = compareFP(angle, sigmoidTable.ulimit);
	 if (c == LT)
	    angle = sigmoidTable.llimit;
	 if (d == GT)
	    angle = sigmoidTable.ulimit;
	 if (verbose)
	    angleFifo2.enq(angle);
	 angleFifo.enq(angle);
	 multiplier.request.put(tuple3(angle, sigmoidTable.rscale, defaultValue));
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Float) get();
	 let result <- mac.response.get();
	 let v = tpl_1(result);
	 Exception e = tpl_2(result);
	 if (pack(e) != 0) $display("mac.exception e=%h v=%h", e, pack(v));
	return v;
     endmethod
   endinterface
endmodule

module [Module] mkSigmoid#(SigmoidTable#(tsz) sigmoidTable, PipeOut#(Float) in)(PipeOut#(Float))
   provisos (Add#(a__, TAdd#(tsz, 2), 32));

   let server <- mkSigmoidServer(sigmoidTable);

   FIFOF#(Float) rfifo <- mkFIFOF;
   rule sigmoidOut;
      let sv <- server.response.get();
      rfifo.enq(sv);
   endrule
   mkConnection(in, server.request);
   return toPipeOut(rfifo);
endmodule

interface DmaSigmoidIfc#(numeric type dsz);
   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numElts);
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) numElts);
   method Bit#(32) tableSize();
   interface ObjectWriteClient#(dsz) dmaClient;
   interface PipeOut#(Bool) pipe;
   interface PipeOut#(Bool) sigmoidTablePipe;
endinterface

module [Module] mkDmaSigmoid#(VectorSource#(dmasz, Vector#(n,Float)) source,
			      VectorSource#(dmasz, Vector#(n,Float)) tableSource,
			      function Module#(DmaVectorSink#(dsz, Vector#(n, Float))) mkSink(PipeOut#(Vector#(n, Float)) pipe_in)
   )
   (DmaSigmoidIfc#(dsz))
   provisos (Bits#(Float, fsz)
	     , Mul#(fsz,n,dmasz)
	     , Add#(1, a__, n)
	     , Add#(b__, n, 4)
	     , Mul#(n, c__, 4)
      );

   Vector#(n, SigmoidTable#(6)) sigmoidTables <- replicateM(mkSigmoidTable);
   Vector#(n, Server#(Float,Float)) sigmoidServers;
   for (Integer i = 0; i < valueOf(n); i = i + 1) begin
      let s <- mkSigmoidServer(sigmoidTables[i]);
      sigmoidServers[i] = s;
   end

   Reg#(Bool) updatingSigmoidTable <- mkReg(False);
   Reg#(Bit#(ObjectOffsetSize)) numElts <- mkReg(0);
   Reg#(Bit#(6)) entryNumber <- mkReg(0);

   FIFOF#(Bool) sigmoidUpdatedFifo <- mkFIFOF();

   PipeOut#(Vector#(4, Float)) sigmoidSourceFunnel <- mkUnfunnel(tableSource.pipe);
   rule updateSigmoidTableRule if (updatingSigmoidTable);
      let vs = sigmoidSourceFunnel.first;
      $display("updateSigmaTableRule vs[0]=%h", vs[0]);
      sigmoidSourceFunnel.deq();
      Vector#(3,Float) vs3 = take(vs);

      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].updateSigmoidTable(entryNumber, vs3);
      end
      if (numElts == 1) begin
	 updatingSigmoidTable <= False;
	 sigmoidUpdatedFifo.enq(True);
      end
      numElts <= numElts - 1;
      entryNumber <= entryNumber + 1;
   endrule

   Reg#(Bit#(32)) countInput <- mkReg(0);
   rule consumeInput if (!updatingSigmoidTable);
      let vs = source.pipe.first;
      source.pipe.deq();
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         sigmoidServers[i].request.put(vs[i]);
      end
      $display("consumeInput countInput=%d vs[0]=%h", countInput+1, vs[0]);
      countInput <= countInput + 1;
   endrule

   Reg#(Bit#(32)) count <- mkReg(0);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule enqResult;
      Vector#(n, Float) vs;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
         let v <- sigmoidServers[i].response.get();
	 vs[i] = v;
      end
      $display("sigmoid count=%d value=%h", count+1, vs);
      count <= count + 1;
      dfifo.enq(vs);
   endrule

   let sinkC <- mkSink(toPipeOut(dfifo));

   method Action start(ObjectPointer pointerA, ObjectPointer pointerB, UInt#(ObjectOffsetSize) numElts);
      source.start(pointerA, 0, pack(numElts));
      sinkC.vector.start(pointerB, 0, pack(numElts));
      $display("sigmoid.start numElts=%d", numElts);
   endmethod
   method Action setSigmoidLimits(Float rscale, Float llimit, Float ulimit);
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 sigmoidTables[i].setSigmoidLimits(rscale, llimit, ulimit);
      end
   endmethod
   method Action updateSigmoidTable(Bit#(32) readPointer, Bit#(32) readOffset, Bit#(32) count);
      entryNumber <= 0;
      numElts <= extend(count);
      updatingSigmoidTable <= True;
      tableSource.start(readPointer, extend(readOffset), 4*extend(count));
   endmethod
   method Bit#(32) tableSize();
      return sigmoidTables[0].tableSize();
   endmethod

   interface ObjectWriteClient dmaClient = sinkC.dmaClient;
   interface PipeOut pipe = sinkC.vector.pipe;
   interface PipeOut sigmoidTablePipe = toPipeOut(sigmoidUpdatedFifo);

endmodule


make RoundMode a constructor argument for mkFloatAdder

import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import FloatingPoint::*;
import DefaultValue::*;
import Randomizable::*;
import Vector::*;
import StmtFSM::*;
import Pipe::*;
import FIFO::*;
import FpMac::*;

typedef Server#(Tuple3#(a,a,RoundMode), Tuple2#(a,Exception)) FloatServer2#(type a);

(* synthesize *)
module mkFloatAdder#(RoundMode rmode)(Server#(Tuple2#(Float,Float),Tuple2#(Float,Exception)));
   let adder <- mkFloatingPointAdder();
   interface Put request;
      method Action put(Tuple2#(Float,Float) req);
	 match { .a, .b } = req;
	 let tpl3 = tuple3(a, b, rmode);
         adder.request.put(tpl3);
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Tuple2#(Float,Exception)) get();
	 let resp <- adder.response.get();
	 return resp;
      endmethod
   endinterface
endmodule

module mkFloatAddPipe#(PipeOut#(Tuple2#(Float,Float)) xypipe)(PipeOut#(Float));
   let adder <- mkFloatAdder(defaultValue);
   FIFOF#(Float) fifo <- mkFIFOF();
   rule consumexy;
      let xy = xypipe.first();
      xypipe.deq;
      adder.request.put(tuple2(tpl_1(xy),tpl_2(xy)));
   endrule
   rule enqout;
      let resp <- adder.response.get();
      fifo.enq(tpl_1(resp));
   endrule
   return toPipeOut(fifo);
endmodule

(* synthesize *)
module mkFloatMultiplier#(RoundMode rmode)(Server#(Tuple2#(Float, Float), Tuple2#(Float,Exception)));
   let multiplier <- mkFPMultiplier(rmode);
   interface Put request;
      method Action put(Tuple2#(Float,Float) req);
         multiplier.request.put(req);
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Tuple2#(Float,Exception)) get();
	 let resp <- multiplier.response.get();
	 return resp;
      endmethod
   endinterface
endmodule

(* synthesize *)
module mkFloatMac#(RoundMode rmode) (Server#(Tuple3#(Maybe#(Float), Float, Float), Tuple2#(Float,Exception)));
   let mac <- mkFpMac(rmode);
   return mac;
endmodule

(* synthesize *)
module mkRandomPipe(PipeOut#(Float));
   let randomizer <- mkConstrainedRandomizer(0, 1024);

   Reg#(Bool) initted <- mkReg(False);
   rule first if (!initted);
      randomizer.cntrl.init();
      initted <= True;
   endrule

   let pipe_out <- mkPipeOut(interface Get#(Float);
				method ActionValue#(Float) get();
				   let v <- randomizer.next();
				   Float f = fromInt32(v);
				   return f;
				endmethod
			     endinterface);
   return pipe_out;
endmodule

module [Module] mkComputeStatesPipe#(PipeOut#(Vector#(n, Float)) pipe_in)(PipeOut#(Vector#(n, Float)))
   provisos(Add#(a__, 1, n)
      );
   FIFOF#(Float) rfifo <- mkFIFOF();
   let randomPipe <- mkRandomPipe();
//   PipeOut#(Vector#(1, Float)) v1randomPipe <- mkFn_to_Pipe(replicate, randomPipe);
//   PipeOut#(Vector#(n, Float)) vrandomPipe <- mkUnfunnel(True, v1randomPipe);

   function Float greater(Float a, Float b);
      if (compareFP(a, b) == GT)
	 return 1.0;
      else
	 return 0.0;
   endfunction
   function Vector#(n, Float) vgreater(Vector#(n, Float) x, Vector#(n, Float) y);
      return map(uncurry(greater), zip(x, y));
   endfunction
//   let joinPipe <- mkJoin(vgreater, pipe_in, vrandomPipe);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule rfoo;
      let r = randomPipe.first();
      randomPipe.deq();
      //$display("random = %x", pack(r));
      rfifo.enq(r);
   endrule
   rule foo;
//      let v = joinPipe.first();
//      joinPipe.deq();
      let vs = pipe_in.first();
      pipe_in.deq();
      let r = rfifo.first();
      rfifo.deq();
      // FIXME: hack!
      Vector#(n, Float) rs = replicate(r);

      let gs = vgreater(vs, rs);

      //$display($format(fshow("vs=")+fshow(vs) + fshow(" rs=") + fshow(rs) + fshow(" states=") + fshow(gs)));
      dfifo.enq(gs);
   endrule

   return toPipeOut(dfifo);
endmodule

module [Module] mkComputeStatesPipe2#(PipeOut#(Vector#(n, Float)) pipe_in, PipeOut#(Vector#(n, Float)) randomPipe)(PipeOut#(Vector#(n, Float)))
   provisos(Add#(a__, 1, n)
      );

   function Float greater(Float a, Float b);
      if (compareFP(a, b) == GT)
	 return 1.0;
      else
	 return 0.0;
   endfunction
   function Vector#(n, Float) vgreater(Vector#(n, Float) x, Vector#(n, Float) y);
      return map(uncurry(greater), zip(x, y));
   endfunction
//   let joinPipe <- mkJoin(vgreater, pipe_in, vrandomPipe);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule foo;
//      let v = joinPipe.first();
//      joinPipe.deq();
      let vs = pipe_in.first();
      pipe_in.deq();
      let rs = randomPipe.first();
      randomPipe.deq();

      let gs = vgreater(vs, rs);

      //$display($format(fshow("vs=")+fshow(pack(vs)) + fshow(" rs=") + fshow(pack(rs)) + fshow(" states=") + fshow(gs)));
      dfifo.enq(gs);
   endrule

   return toPipeOut(dfifo);
endmodule

import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import FloatingPoint::*;
import DefaultValue::*;
import Randomizable::*;
import Vector::*;
import StmtFSM::*;
import Pipe::*;
import FIFO::*;
import FpMac::*;

typedef Server#(Tuple3#(a,a,RoundMode), Tuple2#(a,Exception)) FloatServer2#(type a);

(* synthesize *)
module mkFloatAdder(FloatServer2#(Float));
   let adder <- mkFloatingPointAdder();
   interface Put request;
      method Action put(Tuple3#(Float,Float,RoundMode) req);
         adder.request.put(req);
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Tuple2#(Float,Exception)) get();
	 let resp <- adder.response.get();
	 return resp;
      endmethod
   endinterface
endmodule

module mkFloatAddPipe#(PipeOut#(Tuple2#(Float,Float)) xypipe)(PipeOut#(Float));
   let adder <- mkFloatAdder();
   FIFOF#(Float) fifo <- mkFIFOF();
   rule consumexy;
      let xy = xypipe.first();
      xypipe.deq;
      adder.request.put(tuple3(tpl_1(xy),tpl_2(xy),defaultValue));
   endrule
   rule enqout;
      let resp <- adder.response.get();
      fifo.enq(tpl_1(resp));
   endrule
   return toPipeOut(fifo);
endmodule

(* synthesize *)
module mkFloatMultiplier(FloatServer2#(Float));
   let multiplier <- mkFloatingPointMultiplier();
   interface Put request;
      method Action put(Tuple3#(Float,Float,RoundMode) req);
         multiplier.request.put(req);
      endmethod
   endinterface
   interface Get response;
      method ActionValue#(Tuple2#(Float,Exception)) get();
	 let resp <- multiplier.response.get();
	 return resp;
      endmethod
   endinterface
endmodule

(* synthesize *)
module mkFloatMac#(RoundMode rmode) (Server#(Tuple3#(Maybe#(Float), Float, Float), Tuple2#(Float,Exception)));
   let mac <- mkFpMac(rmode);
   return mac;
endmodule

(* synthesize *)
module mkRandomPipe(PipeOut#(Float));
   let randomizer <- mkConstrainedRandomizer(0, 1024);

   Reg#(Bool) initted <- mkReg(False);
   rule first if (!initted);
      randomizer.cntrl.init();
      initted <= True;
   endrule

   let pipe_out <- mkPipeOut(interface Get#(Float);
				method ActionValue#(Float) get();
				   let v <- randomizer.next();
				   Float f = fromInt32(v);
				   return f;
				endmethod
			     endinterface);
   return pipe_out;
endmodule

module [Module] mkComputeStatesPipe#(PipeOut#(Vector#(n, Float)) pipe_in)(PipeOut#(Vector#(n, Float)))
   provisos(Add#(a__, 1, n)
      );
   FIFOF#(Float) rfifo <- mkFIFOF();
   let randomPipe <- mkRandomPipe();
//   PipeOut#(Vector#(1, Float)) v1randomPipe <- mkFn_to_Pipe(replicate, randomPipe);
//   PipeOut#(Vector#(n, Float)) vrandomPipe <- mkUnfunnel(True, v1randomPipe);

   function Float greater(Float a, Float b);
      if (compareFP(a, b) == GT)
	 return 1.0;
      else
	 return 0.0;
   endfunction
   function Vector#(n, Float) vgreater(Vector#(n, Float) x, Vector#(n, Float) y);
      return map(uncurry(greater), zip(x, y));
   endfunction
//   let joinPipe <- mkJoin(vgreater, pipe_in, vrandomPipe);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule rfoo;
      let r = randomPipe.first();
      randomPipe.deq();
      //$display("random = %x", pack(r));
      rfifo.enq(r);
   endrule
   rule foo;
//      let v = joinPipe.first();
//      joinPipe.deq();
      let vs = pipe_in.first();
      pipe_in.deq();
      let r = rfifo.first();
      rfifo.deq();
      // FIXME: hack!
      Vector#(n, Float) rs = replicate(r);

      let gs = vgreater(vs, rs);

      //$display($format(fshow("vs=")+fshow(vs) + fshow(" rs=") + fshow(rs) + fshow(" states=") + fshow(gs)));
      dfifo.enq(gs);
   endrule

   return toPipeOut(dfifo);
endmodule

module [Module] mkComputeStatesPipe2#(PipeOut#(Vector#(n, Float)) pipe_in, PipeOut#(Vector#(n, Float)) randomPipe)(PipeOut#(Vector#(n, Float)))
   provisos(Add#(a__, 1, n)
      );

   function Float greater(Float a, Float b);
      if (compareFP(a, b) == GT)
	 return 1.0;
      else
	 return 0.0;
   endfunction
   function Vector#(n, Float) vgreater(Vector#(n, Float) x, Vector#(n, Float) y);
      return map(uncurry(greater), zip(x, y));
   endfunction
//   let joinPipe <- mkJoin(vgreater, pipe_in, vrandomPipe);
   FIFOF#(Vector#(n, Float)) dfifo <- mkFIFOF();
   rule foo;
//      let v = joinPipe.first();
//      joinPipe.deq();
      let vs = pipe_in.first();
      pipe_in.deq();
      let rs = randomPipe.first();
      randomPipe.deq();

      let gs = vgreater(vs, rs);

      //$display($format(fshow("vs=")+fshow(pack(vs)) + fshow(" rs=") + fshow(pack(rs)) + fshow(" states=") + fshow(gs)));
      dfifo.enq(gs);
   endrule

   return toPipeOut(dfifo);
endmodule