add bluescopeevent items to portal vector

// 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 GetPut::*;
import Connectable :: *;
import Clocks :: *;
import FIFO::*;
import Portal::*;
import HostInterface::*;
import CtrlMux::*;
import Leds::*;
import MemTypes::*;
import MemServer::*;
import MMU::*;
import PS7LIB::*;
import PPS7LIB::*;

// generated by tool
import FMComms1Request::*;
import FMComms1Indication::*;
import MemServerRequest::*;
import MMURequest::*;
import MemServerIndication::*;
import MMUIndication::*;
import BlueScopeEventPIORequest::*;
import BlueScopeEventPIOIndication::*;

// defined by user
import XilinxCells::*;
import ConnectalXilinxCells::*;
import ConnectalClocks::*;
import BlueScopeEventPIO::*;

import FMComms1ADC::*;
import FMComms1DAC::*;
import FMComms1::*;
import extraXilinxCells::*;

/* Duplicate def here, this is also in ZynqTop */

interface I2C_Pins;
   interface Inout#(Bit#(1)) scl;
   interface Inout#(Bit#(1)) sda;
endinterface

`define BlueScopeEventPIOSampleLength 512

typedef enum { BlueScopeEventPIORequest, BlueScopeEventPIOIndication, FMComms1Request, FMComms1Indication, HostMemServerIndication, HostMemServerRequest, HostMMURequest, HostMMUIndication} IfcNames deriving (Eq,Bits);

interface FMComms1Pins;
   interface FMComms1ADCPins adcpins;
   interface FMComms1DACPins dacpins;
   interface I2C_Pins         i2c1;
   method Bit#(1) ad9548_ref_p();
   method Bit#(1) ad9548_ref_n();

//   (* prefix="" *)
endinterface

/* clk1 is the FCLKCLK1 controlled by software */

module mkConnectalTop#(HostType host)(ConnectalTop#(PhysAddrWidth,64,FMComms1Pins,1));

   Clock clk1 = host.ps7.fclkclk[1];
   C2B ref_clk_as_bit <- mkC2B(clk1);
   Wire#(Bit#(1)) ref_clk_wire <- mkDWire(0);

   rule senddown_clk;
      ref_clk_wire <= ref_clk_as_bit.o();
   endrule

   DiffOut ref_clk <- mkxOBUFDS(ref_clk_wire);

   FMComms1ADC adc <- mkFMComms1ADC();
   FMComms1DAC dac <- mkFMComms1DAC();

   BlueScopeEventPIOIndicationProxy blueScopeEventPIOIndicationProxy <- mkBlueScopeEventPIOIndicationProxy(BlueScopeEventPIOIndication);
   BlueScopeEventPIOControl#(32) bs <- mkBlueScopeEventPIO(`BlueScopeEventPIOSampleLength, blueScopeEventPIOIndicationProxy.ifc);
   BlueScopeEventPIORequestWrapper blueScopeEventPIORequestWrapper <- mkBlueScopeEventPIORequestWrapper(BlueScopeEventPIORequest,bs.requestIfc);

`ifdef USE_FMC_I2C1
   Clock mainclock = host.ps7.fclkclk[0];
   Reset mainreset = host.ps7.fclkreset[0];
   let tscl1 <- mkIOBUF(~host.ps7.i2c[1].scltn, host.ps7.i2c[1].sclo, clocked_by mainclock, reset_by mainreset);
   let tsda1 <- mkIOBUF(~host.ps7.i2c[1].sdatn, host.ps7.i2c[1].sdao, clocked_by mainclock, reset_by mainreset);
   rule sdai1;
      host.ps7.i2c[1].sdai(tsda1.o);
      host.ps7.i2c[1].scli(tscl1.o);
   endrule
   rule watchi2c;
      let a = host.ps7.i2c[1].sclo();
      let b = host.ps7.i2c[1].scltn();
      let c = host.ps7.i2c[1].sdao();
      let d = host.ps7.i2c[1].sdatn();
      bs.bse.dataIn({a, b, tscl1.o, c, d, tsda1.o, 0});
   endrule
`endif

   FMComms1IndicationProxy fmcomms1IndicationProxy <- mkFMComms1IndicationProxy(FMComms1Indication);
   FMComms1 fmcomms1 <- mkFMComms1(fmcomms1IndicationProxy.ifc, dac.dac, adc.adc);
   FMComms1RequestWrapper fmcomms1RequestWrapper <- mkFMComms1RequestWrapper(FMComms1Request, fmcomms1.request);

   Vector#(1,  MemReadClient#(64))   readClients = cons(fmcomms1.readDmaClient, nil);
   Vector#(1, MemWriteClient#(64))  writeClients = cons(fmcomms1.writeDmaClient, nil);
   MMUIndicationProxy hostMMUIndicationProxy <- mkMMUIndicationProxy(HostMMUIndication);
   MMU#(PhysAddrWidth) hostMMU <- mkMMU(0, True, hostMMUIndicationProxy.ifc);
   MMURequestWrapper hostMMURequestWrapper <- mkMMURequestWrapper(HostMMURequest, hostMMU.request);

   MemServerIndicationProxy hostMemServerIndicationProxy <- mkMemServerIndicationProxy(HostMemServerIndication);
   MemServer#(PhysAddrWidth,64,1) dma <- mkMemServerRW(hostMemServerIndicationProxy.ifc, readClients, writeClients, cons(hostMMU,nil));
   MemServerRequestWrapper hostMemServerRequestWrapper <- mkMemServerRequestWrapper(HostMemServerRequest, dma.request);

   Vector#(8,StdPortal) portals;
   portals[0] = fmcomms1RequestWrapper.portalIfc;
   portals[1] = fmcomms1IndicationProxy.portalIfc;
   portals[2] = hostMemServerRequestWrapper.portalIfc;
   portals[3] = hostMemServerIndicationProxy.portalIfc;
   portals[4] = hostMMURequestWrapper.portalIfc;
   portals[5] = hostMMUIndicationProxy.portalIfc;
   portals[6] = blueScopeEventPIORequestWrapper.portalIfc;
   portals[7] = blueScopeEventPIOIndicationProxy.portalIfc;
   let ctrl_mux <- mkSlaveMux(portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = dma.masters;
   interface leds = default_leds;

   interface FMComms1Pins pins;
`ifdef USE_FMC_I2C1
   interface I2C_Pins i2c1;
      interface Inout scl = tscl1.io;
      interface Inout sda = tsda1.io;
   endinterface
`endif
      interface FMComms1ADCPins adcpins = adc.pins;
      interface FMComms1ADCPins dacpins = dac.pins;
      method Bit#(1) ad9548_ref_p();
	 return(ref_clk.read_p());
      endmethod

      method Bit#(1) ad9548_ref_n();
	 return(ref_clk.read_n());
      endmethod
   endinterface
endmodule : mkConnectalTop

// 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 GetPut::*;
import Connectable :: *;
import Clocks :: *;
import FIFO::*;
import Portal::*;
import HostInterface::*;
import CtrlMux::*;
import Leds::*;
import MemTypes::*;
import MemServer::*;
import MMU::*;
import PS7LIB::*;
import PPS7LIB::*;

// generated by tool
import FMComms1Request::*;
import FMComms1Indication::*;
import MemServerRequest::*;
import MMURequest::*;
import MemServerIndication::*;
import MMUIndication::*;
import BlueScopeEventPIORequest::*;
import BlueScopeEventPIOIndication::*;

// defined by user
import XilinxCells::*;
import ConnectalXilinxCells::*;
import ConnectalClocks::*;
import BlueScopeEventPIO::*;

import FMComms1ADC::*;
import FMComms1DAC::*;
import FMComms1::*;
import extraXilinxCells::*;

/* Duplicate def here, this is also in ZynqTop */

interface I2C_Pins;
   interface Inout#(Bit#(1)) scl;
   interface Inout#(Bit#(1)) sda;
endinterface

`define BlueScopeEventPIOSampleLength 512

typedef enum { BlueScopeEventPIORequest, BlueScopeEventPIOIndication, FMComms1Request, FMComms1Indication, HostMemServerIndication, HostMemServerRequest, HostMMURequest, HostMMUIndication} IfcNames deriving (Eq,Bits);

interface FMComms1Pins;
   interface FMComms1ADCPins adcpins;
   interface FMComms1DACPins dacpins;
   interface I2C_Pins         i2c1;
   method Bit#(1) ad9548_ref_p();
   method Bit#(1) ad9548_ref_n();

//   (* prefix="" *)
endinterface

/* clk1 is the FCLKCLK1 controlled by software */

module mkConnectalTop#(HostType host)(ConnectalTop#(PhysAddrWidth,64,FMComms1Pins,1));

   Clock clk1 = host.ps7.fclkclk[1];
   C2B ref_clk_as_bit <- mkC2B(clk1);
   Wire#(Bit#(1)) ref_clk_wire <- mkDWire(0);

   rule senddown_clk;
      ref_clk_wire <= ref_clk_as_bit.o();
   endrule

   DiffOut ref_clk <- mkxOBUFDS(ref_clk_wire);

   FMComms1ADC adc <- mkFMComms1ADC();
   FMComms1DAC dac <- mkFMComms1DAC();

   BlueScopeEventPIOIndicationProxy blueScopeEventPIOIndicationProxy <- mkBlueScopeEventPIOIndicationProxy(BlueScopeEventPIOIndication);
   BlueScopeEventPIOControl#(32) bs <- mkBlueScopeEventPIO(`BlueScopeEventPIOSampleLength, blueScopeEventPIOIndicationProxy.ifc);
   BlueScopeEventPIORequestWrapper blueScopeEventPIORequestWrapper <- mkBlueScopeEventPIORequestWrapper(BlueScopeEventPIORequest,bs.requestIfc);

`ifdef USE_FMC_I2C1
   Clock mainclock = host.ps7.fclkclk[0];
   Reset mainreset = host.ps7.fclkreset[0];
   let tscl1 <- mkIOBUF(~host.ps7.i2c[1].scltn, host.ps7.i2c[1].sclo, clocked_by mainclock, reset_by mainreset);
   let tsda1 <- mkIOBUF(~host.ps7.i2c[1].sdatn, host.ps7.i2c[1].sdao, clocked_by mainclock, reset_by mainreset);
   rule sdai1;
      host.ps7.i2c[1].sdai(tsda1.o);
      host.ps7.i2c[1].scli(tscl1.o);
   endrule
   rule watchi2c;
      let a = host.ps7.i2c[1].sclo();
      let b = host.ps7.i2c[1].scltn();
      let c = host.ps7.i2c[1].sdao();
      let d = host.ps7.i2c[1].sdatn();
      bs.bse.dataIn({a, b, tscl1.o, c, d, tsda1.o, 0});
   endrule
`endif

   FMComms1IndicationProxy fmcomms1IndicationProxy <- mkFMComms1IndicationProxy(FMComms1Indication);
   FMComms1 fmcomms1 <- mkFMComms1(fmcomms1IndicationProxy.ifc, dac.dac, adc.adc);
   FMComms1RequestWrapper fmcomms1RequestWrapper <- mkFMComms1RequestWrapper(FMComms1Request, fmcomms1.request);

   Vector#(1,  MemReadClient#(64))   readClients = cons(fmcomms1.readDmaClient, nil);
   Vector#(1, MemWriteClient#(64))  writeClients = cons(fmcomms1.writeDmaClient, nil);
   MMUIndicationProxy hostMMUIndicationProxy <- mkMMUIndicationProxy(HostMMUIndication);
   MMU#(PhysAddrWidth) hostMMU <- mkMMU(0, True, hostMMUIndicationProxy.ifc);
   MMURequestWrapper hostMMURequestWrapper <- mkMMURequestWrapper(HostMMURequest, hostMMU.request);

   MemServerIndicationProxy hostMemServerIndicationProxy <- mkMemServerIndicationProxy(HostMemServerIndication);
   MemServer#(PhysAddrWidth,64,1) dma <- mkMemServerRW(hostMemServerIndicationProxy.ifc, readClients, writeClients, cons(hostMMU,nil));
   MemServerRequestWrapper hostMemServerRequestWrapper <- mkMemServerRequestWrapper(HostMemServerRequest, dma.request);

   Vector#(6,StdPortal) portals;
   portals[0] = fmcomms1RequestWrapper.portalIfc;
   portals[1] = fmcomms1IndicationProxy.portalIfc;
   portals[2] = hostMemServerRequestWrapper.portalIfc;
   portals[3] = hostMemServerIndicationProxy.portalIfc;
   portals[4] = hostMMURequestWrapper.portalIfc;
   portals[5] = hostMMUIndicationProxy.portalIfc;
   let ctrl_mux <- mkSlaveMux(portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = dma.masters;
   interface leds = default_leds;

   interface FMComms1Pins pins;
`ifdef USE_FMC_I2C1
   interface I2C_Pins i2c1;
      interface Inout scl = tscl1.io;
      interface Inout sda = tsda1.io;
   endinterface
`endif
      interface FMComms1ADCPins adcpins = adc.pins;
      interface FMComms1ADCPins dacpins = dac.pins;
      method Bit#(1) ad9548_ref_p();
	 return(ref_clk.read_p());
      endmethod

      method Bit#(1) ad9548_ref_n();
	 return(ref_clk.read_n());
      endmethod
   endinterface
endmodule : mkConnectalTop


address error on read/write time register MSB

// bsv libraries
import Vector::*;
import FIFO::*;
import RegFile::*;
import SpecialFIFOs::*;

//portz libraries
import Portal::*;
import AxiMasterSlave::*;

interface Directory#(numeric type _n,
		     numeric type _a,
		     numeric type _b,
		     numeric type _c);
   interface Portal#(_n,_a,_b,_c) portalIfc;
   interface ReadOnly#(Bit#(64)) cycles;
   interface Vector#(3,WriteOnly#(Bit#(64))) writeIntervals;
   interface Vector#(3,WriteOnly#(Bit#(64))) readIntervals;
endinterface

typedef Directory#(16,32,32,12) StdDirectory;

module mkStdDirectoryPortalIfc#(RegFileA#(Bit#(32), Bit#(32)) rf)(StdPortal);
   Axi3Slave#(32,32,12) ctrl_mod <- mkAxi3SlaveFromRegFile(rf);
   method Bit#(32) ifcId();
      return 0;
   endmethod
   method Bit#(32) ifcType();
      return 0;
   endmethod
   interface Axi3Slave ctrl = ctrl_mod;
   interface ReadOnly interrupt;
      method Bool _read;
	 return False;
      endmethod
   endinterface
endmodule

module mkStdDirectory#(Vector#(n,StdPortal) portals) (StdDirectory);

   Vector#(3,Wire#(Bit#(64))) writeIntervalWires <- replicateM(mkDWire(64'hfecfecfecfec));
   Vector#(3,Wire#(Bit#(64))) readIntervalWires <- replicateM(mkDWire(64'hfecfecfecfec));

   function WriteOnly#(a) ww(Wire#(a) w);
      return (interface WriteOnly;
		 method Action _write(a x);
		    w <= x;
		 endmethod
	      endinterface);
   endfunction

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

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   let rf = (interface RegFileA#(Bit#(32), Bit#(32));
		method Action upd(Bit#(32) addr, Bit#(32) data);
		   noAction;
		endmethod
		method ActionValue#(Bit#(32)) sub(Bit#(32) _addr);
		   let base = 128;
		   let cco = fromInteger(valueOf(TAdd#(TMul#(2,n),4)))+base;
		   let addr = _addr[15:0];
		   if (addr == 0+base)
		      return 1; // directory version
		   else if (addr == 1+base)
		      return `TimeStamp;
		   else if (addr == 2+base)
		      return fromInteger(valueOf(n));
		   else if (addr == 3+base)
		      return 16; // portal Addr bits
		   else if (addr < cco) begin
		      let idx = (addr-4-base);
		      if (idx[0] == 0)
		   	 return portals[idx>>1].ifcId;
		      else
		   	 return portals[idx>>1].ifcType;
		   end
		   else if (addr == cco) begin
		      snapshot <= truncate(cycle_count);
		      return cycle_count[63:32];
		   end
		   else if (addr == cco+1)
		      return snapshot;
		   else if (addr < cco+8) /* address in range [cco+2 .. cco+7] */ // read low order bits
      		      return truncate(append(readIntervalWires,writeIntervalWires)[addr-(cco+2)]);
		   else if (addr < cco+13) /* address in range [cco+8 .. cco+13] */ // read high order bits
      		      return truncate(append(readIntervalWires,writeIntervalWires)[addr-(cco+8)]>>32);
		   else begin
      		      $display("directory addr out bounds %d", addr);
		      return 0;
		   end
		endmethod
      	     endinterface);
   let ifc <- mkStdDirectoryPortalIfc(rf);
   interface StdPortal portalIfc = ifc;
   interface ReadOnly cycles = regToReadOnly(cycle_count);
   interface Vector writeIntervals = map(ww, writeIntervalWires);
   interface Vector readIntervals  = map(ww, readIntervalWires);

endmodule

// bsv libraries
import Vector::*;
import FIFO::*;
import RegFile::*;
import SpecialFIFOs::*;

//portz libraries
import Portal::*;
import AxiMasterSlave::*;

interface Directory#(numeric type _n,
		     numeric type _a,
		     numeric type _b,
		     numeric type _c);
   interface Portal#(_n,_a,_b,_c) portalIfc;
   interface ReadOnly#(Bit#(64)) cycles;
   interface Vector#(3,WriteOnly#(Bit#(64))) writeIntervals;
   interface Vector#(3,WriteOnly#(Bit#(64))) readIntervals;
endinterface

typedef Directory#(16,32,32,12) StdDirectory;

module mkStdDirectoryPortalIfc#(RegFileA#(Bit#(32), Bit#(32)) rf)(StdPortal);
   Axi3Slave#(32,32,12) ctrl_mod <- mkAxi3SlaveFromRegFile(rf);
   method Bit#(32) ifcId();
      return 0;
   endmethod
   method Bit#(32) ifcType();
      return 0;
   endmethod
   interface Axi3Slave ctrl = ctrl_mod;
   interface ReadOnly interrupt;
      method Bool _read;
	 return False;
      endmethod
   endinterface
endmodule

module mkStdDirectory#(Vector#(n,StdPortal) portals) (StdDirectory);

   Vector#(3,Wire#(Bit#(64))) writeIntervalWires <- replicateM(mkDWire(64'hfecfecfecfec));
   Vector#(3,Wire#(Bit#(64))) readIntervalWires <- replicateM(mkDWire(64'hfecfecfecfec));

   function WriteOnly#(a) ww(Wire#(a) w);
      return (interface WriteOnly;
		 method Action _write(a x);
		    w <= x;
		 endmethod
	      endinterface);
   endfunction

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

   rule count;
      cycle_count <= cycle_count+1;
   endrule

   let rf = (interface RegFileA#(Bit#(32), Bit#(32));
		method Action upd(Bit#(32) addr, Bit#(32) data);
		   noAction;
		endmethod
		method ActionValue#(Bit#(32)) sub(Bit#(32) _addr);
		   let base = 128;
		   let cco = fromInteger(valueOf(TAdd#(TMul#(2,n),4)))+base;
		   let addr = _addr[15:0];
		   if (addr == 0+base)
		      return 1; // directory version
		   else if (addr == 1+base)
		      return `TimeStamp;
		   else if (addr == 2+base)
		      return fromInteger(valueOf(n));
		   else if (addr == 3+base)
		      return 16; // portal Addr bits
		   else if (addr < cco) begin
		      let idx = (addr-4-base);
		      if (idx[0] == 0)
		   	 return portals[idx>>1].ifcId;
		      else
		   	 return portals[idx>>1].ifcType;
		   end
		   else if (addr == cco) begin
		      snapshot <= truncate(cycle_count);
		      return cycle_count[63:32];
		   end
		   else if (addr == cco+1)
		      return snapshot;
		   else if (addr < cco+8) /* address in range [cco+2 .. cco+7] */ // read low order bits
      		      return truncate(append(readIntervalWires,writeIntervalWires)[addr-(cco+2)]);
		   else if (addr < cco+13) /* address in range [cco+8 .. cco+13] */ // read high order bits
      		      return truncate(append(readIntervalWires,writeIntervalWires)[addr-(cco+2)]>>32);
		   else begin
      		      $display("directory addr out bounds %d", addr);
		      return 0;
		   end
		endmethod
      	     endinterface);
   let ifc <- mkStdDirectoryPortalIfc(rf);
   interface StdPortal portalIfc = ifc;
   interface ReadOnly cycles = regToReadOnly(cycle_count);
   interface Vector writeIntervals = map(ww, writeIntervalWires);
   interface Vector readIntervals  = map(ww, readIntervalWires);

endmodule


simple refactor of Bsim Ctrl interface in BsimTop

// 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 Clocks            :: *;
import Vector            :: *;
import FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import AxiMasterSlave    :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import MemTypes          :: *;
import AxiDma            :: *;
import HostInterface     :: *;
import CtrlMux           :: *;
import ClientServer      :: *;
import MemSlaveEngine    :: *;
import MemMasterEngine   :: *;
import PCIE              :: *;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

// implemented in BsimCtrl.cxx
import "BDPI" function Action                 initPortal();
import "BDPI" function Bool                   checkForRequest(Bit#(32) v);
import "BDPI" function ActionValue#(Bit#(64)) getRequest32(Bit#(32) v);
import "BDPI" function Action                 readResponse32(Bit#(32) d, Bit#(32) tag);
import "BDPI" function Action                 interruptLevel(Bit#(1) d);

// implemented in BsimDma.cxx
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 mkBsimCtrlReadWrite(PhysMemMaster#(clientAddrWidth, clientBusWidth))
   provisos(Add#(a__, 32, clientAddrWidth), Add#(b__, 32, clientBusWidth));
   FIFO#(Bit#(clientBusWidth)) wf <- mkPipelineFIFO;
   Reg#(Bit#(32)) cycles      <- mkReg(0);
   rule count;
      cycles <= cycles + 1;
   endrule

   let verbose = False;
   let init_fsm <- mkOnce(initPortal());

   rule init_rule;
      init_fsm.start;
   endrule
   interface PhysMemReadClient read_client;
     interface Get readReq;
	 method ActionValue#(PhysMemRequest#(clientAddrWidth)) get() if (checkForRequest(0));
	 //$write("req_ar: ");
	 let ra <- getRequest32(0);
	 //$display("ra=%h", ra);
	 let burstLen = fromInteger(valueOf(clientBusWidth) / 8);
	 if (verbose) $display("\n%d BsimHost.readReq addr=%h burstLen=%d", cycles, ra, burstLen);
	 return PhysMemRequest { addr: extend(ra[31:0]), burstLen: burstLen, tag: truncate(ra[63:32])};
	 endmethod
     endinterface
     interface Put readData;
	 method Action put(MemData#(clientBusWidth) rd);
	 //$display("resp_read: rd=%h", rd);
	 if (verbose) $display("%d BsimHost.readData %h", cycles, rd.data);
	 readResponse32(truncate(rd.data), extend(rd.tag));
	 endmethod
     endinterface
   endinterface
   interface PhysMemWriteClient write_client;
     interface Get writeReq;
	 method ActionValue#(PhysMemRequest#(clientAddrWidth)) get() if (checkForRequest(1));
	 let wd <- getRequest32(1);
	 wf.enq(extend(wd[63:32]));
	 let burstLen = fromInteger(valueOf(clientBusWidth) / 8);
	 if (verbose) $display("\n%d BsimHost.writeReq addr/data=%h burstLen=%d", cycles, wd, burstLen);
	 return PhysMemRequest { addr: extend(wd[31:0]), burstLen: burstLen, tag: 0 };
	 endmethod
     endinterface
     interface Get writeData;
	 method ActionValue#(MemData#(clientBusWidth)) get;
	 wf.deq;
	 if (verbose) $display("%d BsimHost.writeData %h", cycles, wf.first);
	 return MemData { data: wf.first, tag: 0, last: True };
	 endmethod
     endinterface
     interface Put writeDone;
	 method Action put(Bit#(MemTagSize) resp);
	 if (verbose) $display("%d BsimHost.writeDone %d", cycles, resp);
	 endmethod
     endinterface
   endinterface
endmodule

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

module mkAxi3Slave(Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth));

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

   Reg#(Bit#(serverAddrWidth)) readAddrr <- mkReg(0);
   Reg#(Bit#(5))  readLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) readId <- mkReg(0);
   Reg#(Bit#(serverAddrWidth)) writeAddrr <- mkReg(0);
   Reg#(Bit#(5))  writeLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) writeId <- 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)) cycle <- 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), Axi3ReadRequest#(serverAddrWidth,serverIdWidth)))  readDelayFifo <- mkSizedFIFOF(readLatency_I);
   FIFOF#(Tuple2#(Bit#(64),Axi3WriteRequest#(serverAddrWidth,serverIdWidth))) writeDelayFifo <- mkSizedFIFOF(writeLatency_I);

   FIFOF#(Tuple2#(Bit#(64), Axi3WriteResponse#(serverIdWidth))) bFifo <- mkSizedFIFOF(writeLatency_I);

   rule increment_cycle;
      cycle <= cycle+1;
   endrule

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

   interface Put req_ar;
      method Action put(Axi3ReadRequest#(serverAddrWidth,serverIdWidth) req);
	 //if(id==1) $display("mkBsimHost::req_ar_a: %d %d", req.id, cycle-last_reqAr);
	 //last_reqAr <= cycle;
	 readDelayFifo.enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(serverBusWidth,serverIdWidth)) get if (((readLen > 0) || (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency)) && read_jitter);
	 Bit#(5) read_len = ?;
	 Bit#(serverAddrWidth) read_addr = ?;
	 Bit#(serverIdWidth) read_id = ?;
	 Bit#(8) handle = ?;
	 if (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency) begin
	    req_ar_b_ts <= cycle;
	    let req = tpl_2(readDelayFifo.first);
	    readDelayFifo.deq;
	    read_len = extend(req.len)+1;
	    read_addr = req.address;
	    read_id = req.id;
	    handle = req.address[39:32];
	    //if(id==1) $display("mkBsimHost::resp_read_a: %d %d %d", req.id,  cycle-last_read_eob, req.len);
	    //last_read_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_read_b: %d %d", readId,  cycle-last_read_eob);
	    //last_read_eob <= cycle;
	    handle = readAddrr[39:32];
	    read_addr = readAddrr;
	    read_id = readId;
	    read_len = readLen;
	 end
	 Bit#(serverBusWidth) v <- rw.read_pareff(extend(handle), read_addr[31:0]);
	 readLen <= read_len - 1;
	 readId <= read_id;
	 readAddrr <= read_addr + fromInteger(valueOf(serverBusWidth)/8);
	 //$display("mkBsimHost::resp_read id=%d %d", read_id, read_len);
	 return Axi3ReadResponse { data: v, resp: 0, last: pack(readLen == 1), id: read_id};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(serverAddrWidth,serverIdWidth) req);
	 //$display("mkBsimHost::req_aw id=%d", req.id);
	 writeDelayFifo.enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(serverBusWidth,serverIdWidth) resp) if (((writeLen > 0) || (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency)) && write_jitter);
	 Bit#(5) write_len = ?;
	 Bit#(serverAddrWidth) write_addr = ?;
	 Bit#(serverIdWidth) write_id = ?;
	 Bit#(8) handle = ?;
	 if (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency) begin
	    req_aw_b_ts <= cycle;
	    let req = tpl_2(writeDelayFifo.first);
	    writeDelayFifo.deq;
	    write_addr = req.address;
	    write_len = extend(req.len)+1;
	    write_id = req.id;
	    handle = req.address[39:32];
	    //$display("mkBsimHost::resp_write_a: %d %d", req.id,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_write_b: %d %d", writeId,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	    handle = writeAddrr[39:32];
	    write_len = writeLen;
	    write_addr = writeAddrr;
	    write_id = writeId;
	 end
	 rw.write_pareff(extend(handle), write_addr[31:0], resp.data);
	 //$display("write_resp(%d): handle=%d addr=%h v=%h", cycle, handle, write_addr, resp.data);
	 writeId <= write_id;
	 writeLen <= write_len - 1;
	 writeAddrr <= write_addr + fromInteger(valueOf(serverBusWidth)/8);
	 if (write_len == 1) begin
	    bFifo.enq(tuple2(cycle,Axi3WriteResponse { id: write_id, resp: 0 }));
	 end
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(serverIdWidth)) get if ((cycle-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
      endmethod
   endinterface

endmodule

module  mkBsimHost#(Clock double_clock, Reset double_reset)(BsimHost#(clientAddrWidth, clientBusWidth, clientIdWidth,
			      serverAddrWidth, serverBusWidth, serverIdWidth,
			      nSlaves))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth),
             Add#(a__, 32, clientAddrWidth), Add#(b__, 32, clientBusWidth));

   Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth)) servers <- replicateM(mkAxi3Slave);
   PhysMemMaster#(clientAddrWidth, clientBusWidth) crw <- mkBsimCtrlReadWrite();

   interface axi_servers = servers;
   interface PhysMemMaster mem_client = crw;
   interface doubleClock = double_clock;
   interface doubleReset = double_reset;
endmodule

module  mkBsimTop(Empty)
   provisos (SelectBsimRdmaReadWrite#(DataBusWidth));
   let divider <- mkClockDivider(2);
   Clock doubleClock = divider.fastClock;
   Clock singleClock = divider.slowClock;
   Reset doubleReset <- exposeCurrentReset;
   let single_reset <- mkReset(2, True, singleClock);
   Reset singleReset = single_reset.new_rst;
   BsimHost#(32,32,12,PhysAddrWidth,DataBusWidth,6,NumberOfMasters) host <- mkBsimHost(clocked_by singleClock, reset_by singleReset, doubleClock, doubleReset);
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`endif
       clocked_by singleClock, reset_by singleReset);
   Vector#(NumberOfMasters,Axi3Master#(PhysAddrWidth,DataBusWidth,6)) m_axis <- mapM(mkAxiDmaMaster,top.masters, clocked_by singleClock, reset_by singleReset);
   mapM(uncurry(mkConnection),zip(m_axis, host.axi_servers), clocked_by singleClock, reset_by singleReset);
`ifndef BSIM_EXERCISE_MEM_MASTER_SLAVE
   mkConnection(host.mem_client, top.slave, clocked_by singleClock, reset_by singleReset);
`else
   PciId masterPciId = unpack(22);
   PciId slavePciId = unpack(23);
   MemMasterEngine masterEngine <- mkMemMasterEngine(masterPciId, clocked_by singleClock, reset_by singleReset);
   MemSlaveEngine#(32) slaveEngine <- mkMemSlaveEngine(slavePciId, clocked_by singleClock, reset_by singleReset);
   mkConnection(host.mem_client, slaveEngine.slave, clocked_by singleClock, reset_by singleReset);
   mkConnection(slaveEngine.tlp.request, masterEngine.tlp.response, clocked_by singleClock, reset_by singleReset);
   mkConnection(slaveEngine.tlp.response, masterEngine.tlp.request, clocked_by singleClock, reset_by singleReset);
   mkConnection(masterEngine.master, top.slave, clocked_by singleClock, reset_by singleReset);
`endif

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule int_rule;
      interruptLevel(truncate(pack(intr_mux)));
   endrule

`ifdef BSIMRESPONDER
   `BSIMRESPONDER (top.pins);
`endif
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 Clocks            :: *;
import Vector            :: *;
import FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import AxiMasterSlave    :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import MemTypes          :: *;
import AxiDma            :: *;
import HostInterface     :: *;
import CtrlMux           :: *;
import ClientServer      :: *;
import MemSlaveEngine    :: *;
import MemMasterEngine   :: *;
import PCIE              :: *;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

// implemented in BsimCtrl.cxx
import "BDPI" function Action                 initPortal();
import "BDPI" function Bool                   checkForRequest(Bit#(32) v);
import "BDPI" function ActionValue#(Bit#(64)) getRequest32(Bit#(32) v);
import "BDPI" function Action                 readResponse32(Bit#(32) d, Bit#(32) tag);
import "BDPI" function Action                 interruptLevel(Bit#(1) d);

// implemented in BsimDma.cxx
import "BDPI" function Action pareff(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
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);

typedef struct {
   Bit#(MemTagSize) tag;
   Bit#(asz) addr;
} BsimReadRequest#(numeric type asz, numeric type dsz) deriving(Eq, Bits);

typedef struct {
   Bit#(dsz) data;
   Bit#(asz) addr;
} BsimWriteRequest#(numeric type asz, numeric type dsz) deriving(Eq, Bits);

interface BsimCtrlReadWrite#(numeric type asz, numeric type dsz);
   method ActionValue#(BsimReadRequest#(asz, dsz)) readRequest();
   method Action readResponse(Bit#(dsz) d, Bit#(MemTagSize) tag);
   method ActionValue#(BsimWriteRequest#(asz, dsz)) writeRequest();
endinterface

typeclass SelectBsimCtrlReadWrite#(numeric type asz, numeric type dsz);
   module selectBsimCtrlReadWrite(BsimCtrlReadWrite#(asz,dsz) ifc);
endtypeclass

instance SelectBsimCtrlReadWrite#(32,32);
   module selectBsimCtrlReadWrite(BsimCtrlReadWrite#(32,32) ifc);
      method ActionValue#(BsimReadRequest#(32,32)) readRequest() if (checkForRequest(0));
	 let rv <- getRequest32(0);
	 return BsimReadRequest{tag: truncate(rv[63:32]), addr:rv[31:0]};
      endmethod
      method Action readResponse(Bit#(32) d, Bit#(MemTagSize) tag);
	 readResponse32(d, extend(tag));
      endmethod
      method ActionValue#(BsimWriteRequest#(32, 32)) writeRequest() if (checkForRequest(1));
	 let rv <- getRequest32(1);
	 return BsimWriteRequest{data: rv[63:32], addr: rv[31:0]};
      endmethod
   endmodule
endinstance

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

module mkAxi3Slave(Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth));

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

   Reg#(Bit#(serverAddrWidth)) readAddrr <- mkReg(0);
   Reg#(Bit#(5))  readLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) readId <- mkReg(0);
   Reg#(Bit#(serverAddrWidth)) writeAddrr <- mkReg(0);
   Reg#(Bit#(5))  writeLen <- mkReg(0);
   Reg#(Bit#(serverIdWidth)) writeId <- 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)) cycle <- 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), Axi3ReadRequest#(serverAddrWidth,serverIdWidth)))  readDelayFifo <- mkSizedFIFOF(readLatency_I);
   FIFOF#(Tuple2#(Bit#(64),Axi3WriteRequest#(serverAddrWidth,serverIdWidth))) writeDelayFifo <- mkSizedFIFOF(writeLatency_I);

   FIFOF#(Tuple2#(Bit#(64), Axi3WriteResponse#(serverIdWidth))) bFifo <- mkSizedFIFOF(writeLatency_I);

   rule increment_cycle;
      cycle <= cycle+1;
   endrule

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

   interface Put req_ar;
      method Action put(Axi3ReadRequest#(serverAddrWidth,serverIdWidth) req);
	 //if(id==1) $display("mkBsimHost::req_ar_a: %d %d", req.id, cycle-last_reqAr);
	 //last_reqAr <= cycle;
	 readDelayFifo.enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(serverBusWidth,serverIdWidth)) get if (((readLen > 0) || (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency)) && read_jitter);
	 Bit#(5) read_len = ?;
	 Bit#(serverAddrWidth) read_addr = ?;
	 Bit#(serverIdWidth) read_id = ?;
	 Bit#(8) handle = ?;
	 if (readLen == 0 && (cycle-tpl_1(readDelayFifo.first)) > readLatency) begin
	    req_ar_b_ts <= cycle;
	    let req = tpl_2(readDelayFifo.first);
	    readDelayFifo.deq;
	    read_len = extend(req.len)+1;
	    read_addr = req.address;
	    read_id = req.id;
	    handle = req.address[39:32];
	    //if(id==1) $display("mkBsimHost::resp_read_a: %d %d %d", req.id,  cycle-last_read_eob, req.len);
	    //last_read_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_read_b: %d %d", readId,  cycle-last_read_eob);
	    //last_read_eob <= cycle;
	    handle = readAddrr[39:32];
	    read_addr = readAddrr;
	    read_id = readId;
	    read_len = readLen;
	 end
	 Bit#(serverBusWidth) v <- rw.read_pareff(extend(handle), read_addr[31:0]);
	 readLen <= read_len - 1;
	 readId <= read_id;
	 readAddrr <= read_addr + fromInteger(valueOf(serverBusWidth)/8);
	 //$display("mkBsimHost::resp_read id=%d %d", read_id, read_len);
	 return Axi3ReadResponse { data: v, resp: 0, last: pack(readLen == 1), id: read_id};
      endmethod
   endinterface
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(serverAddrWidth,serverIdWidth) req);
	 //$display("mkBsimHost::req_aw id=%d", req.id);
	 writeDelayFifo.enq(tuple2(cycle,req));
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(serverBusWidth,serverIdWidth) resp) if (((writeLen > 0) || (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency)) && write_jitter);
	 Bit#(5) write_len = ?;
	 Bit#(serverAddrWidth) write_addr = ?;
	 Bit#(serverIdWidth) write_id = ?;
	 Bit#(8) handle = ?;
	 if (writeLen == 0 && (cycle-tpl_1(writeDelayFifo.first)) > writeLatency) begin
	    req_aw_b_ts <= cycle;
	    let req = tpl_2(writeDelayFifo.first);
	    writeDelayFifo.deq;
	    write_addr = req.address;
	    write_len = extend(req.len)+1;
	    write_id = req.id;
	    handle = req.address[39:32];
	    //$display("mkBsimHost::resp_write_a: %d %d", req.id,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	 end
	 else begin
	    //$display("mkBsimHost::resp_write_b: %d %d", writeId,  cycle-last_write_eob);
	    //last_write_eob <= cycle;
	    handle = writeAddrr[39:32];
	    write_len = writeLen;
	    write_addr = writeAddrr;
	    write_id = writeId;
	 end
	 rw.write_pareff(extend(handle), write_addr[31:0], resp.data);
	 //$display("write_resp(%d): handle=%d addr=%h v=%h", cycle, handle, write_addr, resp.data);
	 writeId <= write_id;
	 writeLen <= write_len - 1;
	 writeAddrr <= write_addr + fromInteger(valueOf(serverBusWidth)/8);
	 if (write_len == 1) begin
	    bFifo.enq(tuple2(cycle,Axi3WriteResponse { id: write_id, resp: 0 }));
	 end
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(serverIdWidth)) get if ((cycle-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
      endmethod
   endinterface

endmodule

module  mkBsimHost#(Clock double_clock, Reset double_reset)(BsimHost#(clientAddrWidth, clientBusWidth, clientIdWidth,
			      serverAddrWidth, serverBusWidth, serverIdWidth,
			      nSlaves))
   provisos (SelectBsimRdmaReadWrite#(serverBusWidth),
	     SelectBsimCtrlReadWrite#(clientAddrWidth, clientBusWidth));

   Vector#(nSlaves,Axi3Slave#(serverAddrWidth,  serverBusWidth, serverIdWidth)) servers <- replicateM(mkAxi3Slave);
   BsimCtrlReadWrite#(clientAddrWidth,clientBusWidth) crw <- selectBsimCtrlReadWrite();
   FIFO#(Bit#(clientBusWidth)) wf <- mkPipelineFIFO;
   let init_fsm <- mkOnce(initPortal());

   rule init_rule;
      init_fsm.start;
   endrule

   let verbose = False;
    Reg#(Bit#(32)) cycles      <- mkReg(0);
    rule count;
       cycles <= cycles + 1;
    endrule

   interface axi_servers = servers;
   interface PhysMemMaster mem_client;
      interface PhysMemReadClient read_client;
        interface Get readReq;
	 method ActionValue#(PhysMemRequest#(clientAddrWidth)) get();
	    //$write("req_ar: ");
	    let ra <- crw.readRequest();
	    //$display("ra=%h", ra);
	    let burstLen = fromInteger(valueOf(clientBusWidth) / 8);
	    if (verbose) $display("\n%d BsimHost.readReq addr=%h burstLen=%d", cycles, ra, burstLen);
	    return PhysMemRequest { addr: ra.addr, burstLen: burstLen, tag: ra.tag};
	 endmethod
        endinterface
        interface Put readData;
	 method Action put(MemData#(clientBusWidth) rd);
	    //$display("resp_read: rd=%h", rd);
	    if (verbose) $display("%d BsimHost.readData %h", cycles, rd.data);
	    crw.readResponse(rd.data, rd.tag);
	 endmethod
        endinterface
      endinterface
      interface PhysMemWriteClient write_client;
        interface Get writeReq;
	 method ActionValue#(PhysMemRequest#(clientAddrWidth)) get();
	    let wd <- crw.writeRequest;
	    wf.enq(wd.data);
	    let burstLen = fromInteger(valueOf(clientBusWidth) / 8);
	    if (verbose) $display("\n%d BsimHost.writeReq addr/data=%h burstLen=%d", cycles, wd, burstLen);
	    return PhysMemRequest { addr: wd.addr, burstLen: burstLen, tag: 0 };
	 endmethod
        endinterface
        interface Get writeData;
	 method ActionValue#(MemData#(clientBusWidth)) get;
	    wf.deq;
	    if (verbose) $display("%d BsimHost.writeData %h", cycles, wf.first);
	    return MemData { data: wf.first, tag: 0, last: True };
	 endmethod
        endinterface
        interface Put writeDone;
	 method Action put(Bit#(MemTagSize) resp);
	    if (verbose) $display("%d BsimHost.writeDone %d", cycles, resp);
	 endmethod
        endinterface
      endinterface
   endinterface
   interface doubleClock = double_clock;
   interface doubleReset = double_reset;
endmodule

module  mkBsimTop(Empty)
   provisos (SelectBsimRdmaReadWrite#(DataBusWidth));
   let divider <- mkClockDivider(2);
   Clock doubleClock = divider.fastClock;
   Clock singleClock = divider.slowClock;
   Reset doubleReset <- exposeCurrentReset;
   let single_reset <- mkReset(2, True, singleClock);
   Reset singleReset = single_reset.new_rst;
   BsimHost#(32,32,12,PhysAddrWidth,DataBusWidth,6,NumberOfMasters) host <- mkBsimHost(clocked_by singleClock, reset_by singleReset, doubleClock, doubleReset);
`ifdef IMPORT_HOSTIF
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(clocked_by singleClock, reset_by singleReset, host);
`else
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(clocked_by singleClock, reset_by singleReset);
`endif
   Vector#(NumberOfMasters,Axi3Master#(PhysAddrWidth,DataBusWidth,6)) m_axis <- mapM(mkAxiDmaMaster,top.masters, clocked_by singleClock, reset_by singleReset);
   mapM(uncurry(mkConnection),zip(m_axis, host.axi_servers), clocked_by singleClock, reset_by singleReset);
`ifndef BSIM_EXERCISE_MEM_MASTER_SLAVE
   mkConnection(host.mem_client, top.slave, clocked_by singleClock, reset_by singleReset);
`else
   PciId masterPciId = unpack(22);
   PciId slavePciId = unpack(23);
   MemMasterEngine masterEngine <- mkMemMasterEngine(masterPciId, clocked_by singleClock, reset_by singleReset);
   MemSlaveEngine#(32) slaveEngine <- mkMemSlaveEngine(slavePciId, clocked_by singleClock, reset_by singleReset);
   mkConnection(host.mem_client, slaveEngine.slave, clocked_by singleClock, reset_by singleReset);
   mkConnection(slaveEngine.tlp.request, masterEngine.tlp.response, clocked_by singleClock, reset_by singleReset);
   mkConnection(slaveEngine.tlp.response, masterEngine.tlp.request, clocked_by singleClock, reset_by singleReset);
   mkConnection(masterEngine.master, top.slave, clocked_by singleClock, reset_by singleReset);
`endif

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule int_rule;
      interruptLevel(truncate(pack(intr_mux)));
   endrule

`ifdef BSIMRESPONDER
   `BSIMRESPONDER (top.pins);
`endif
endmodule


indentation

indentation

Change-Id: I7bb92e0479328007d480f5a0ae51d910d40d7424

// 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 Clocks            :: *;
import GetPut            :: *;
import FIFO              :: *;
import Connectable       :: *;
import ClientServer      :: *;
import DefaultValue      :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import Xilinx            :: *;
import PCIEWRAPPER       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemSlaveEngine    :: *;
import MemMasterEngine   :: *;
import PcieCsr           :: *;
import MemSlave          :: *;
import MemTypes          :: *;
import Bscan             :: *;
`ifndef BSIM
import PcieEndpointX7    :: *;
`endif
import PcieHostTypeIF    :: *;

`ifndef DataBusWidth
`define DataBusWidth 64
`endif
`ifndef PinType
`define PinType Empty
`endif

`ifdef USES_BSCAN
`define BSCAN_ARG  local_bscan
`else
`define BSCAN_ARG
`endif

// implemented in TlpReplay.cxx
import "BDPI" function Action put_tlp(TLPData#(16) d);
import "BDPI" function ActionValue#(TLPData#(16)) get_tlp();
import "BDPI" function Bool can_put_tlp();
import "BDPI" function Bool can_get_tlp();

(* synthesize *)
module  mkPcieHost#(PciId my_pciId)(PcieHost#(DataBusWidth, NumberOfMasters));
   Clock epClock125 <- exposeCurrentClock();
   Reset epReset125 <- exposeCurrentReset();
   let dispatcher <- mkTLPDispatcher;
   let arbiter    <- mkTLPArbiter;
   Vector#(NumberOfMasters,MemSlaveEngine#(DataBusWidth)) sEngine <- replicateM(mkMemSlaveEngine(my_pciId));
   Vector#(NumberOfMasters,MemSlave#(40,DataBusWidth)) slavearr;
   MemInterrupt intr <- mkMemInterrupt(my_pciId);
   BscanTop bscan <- mkBscanTop(3); // Use USER3  (JTAG IDCODE address 0x22)
   BscanLocal lbscan <- mkBscanLocal(bscan, clocked_by bscan.tck, reset_by bscan.rst);

   Vector#(PortMax, MemMasterEngine) mvec;
   for (Integer i = 0; i < valueOf(PortMax) - 1 + valueOf(NumberOfMasters); i=i+1) begin
       let tlp;
       if (i == portInterrupt)
           tlp = intr.tlp;
       else if (i >= portAxi) begin
           tlp = sEngine[i - portAxi].tlp;
           slavearr[i - portAxi] = sEngine[i - portAxi].slave;
       end
       else begin
           mvec[i] <- mkMemMasterEngine(my_pciId);
           tlp = mvec[i].tlp;
       end
       mkConnection((interface Server;
                        interface response = dispatcher.out[i];
                        interface request = arbiter.in[i];
                     endinterface), tlp);
   end

   PcieTracer  traceif <- mkPcieTracer();
   mkConnection(traceif.bus, (interface Client;
                                 interface request = arbiter.outToBus;
                                 interface response = dispatcher.inFromBus;
                              endinterface));
`ifndef BSIM
   Reg#(Bit#(TAdd#(TlpTraceAddrSize,1))) bscanPcieTraceBramWrAddrReg <- mkReg(0);
   BscanBram#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) pcieBscanBram <- mkBscanBram(127, bscanPcieTraceBramWrAddrReg, lbscan.loc[1]);
   mkConnection(pcieBscanBram.bramClient, traceif.tlpdata.bscanBramServer);
   rule tdorule;
      lbscan.loc[1].tdo(pcieBscanBram.data_out());
   endrule
`endif

   PcieControlAndStatusRegs csr <- mkPcieControlAndStatusRegs(traceif.tlpdata);
   MemSlave#(32,32) my_slave <- mkMemSlave(csr.client);
   mkConnection(mvec[portConfig].master, my_slave);

   interface msixEntry = csr.msixEntry;
   interface master = mvec[portPortal].master;
   interface slave = slavearr;
   interface interruptRequest = intr.interruptRequest;
   interface pci = traceif.pci;
   interface BscanTop bscanif = lbscan.loc[0];
endmodule: mkPcieHost

`ifndef IMPORT_HOSTIF
(* synthesize *)
`endif
module mkSynthesizeablePortalTop
`ifdef IMPORT_HOSTIF
     #(HostType host)
`endif
     (PortalTop#(40, DataBusWidth, PinType, NumberOfMasters));
   Clock defaultClock <- exposeCurrentClock();
   //BscanTop local_bscan <- mkBscanTop(3); // Use USER3  (JTAG IDCODE address 0x22)
`ifdef IMPORT_HOSTIF
   let top <- mkPortalTop(host);
`else
   let top <- mkPortalTop(`BSCAN_ARG);
`endif
   interface masters = top.masters;
   interface slave = top.slave;
   interface interrupt = top.interrupt;
   interface leds = top.leds;
   interface pins = top.pins;
endmodule

interface PcieTop#(type ipins);
`ifndef BSIM
   (* prefix="PCIE" *)
   interface PciewrapPci_exp#(PcieLanes) pcie;
   (* always_ready *)
   method Bit#(NumLeds) leds();
   (* prefix="" *)
   interface ipins       pins;
`endif
endinterface

module mkPcieHostTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)(PcieHostTop);

`ifdef BSIM
   let dc <- exposeCurrentClock;
   let dr <- exposeCurrentReset;
   Clock epClock125 = dc;
   Reset epReset125 = dr;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(PciId{ bus:0, dev:0, func:0});
   // connect pciehost.pci to bdip functions here
   rule from_bdpi if (can_get_tlp);
      TLPData#(16) foo <- get_tlp;
      pciehost.pci.response.put(foo);
      //$display("from_bdpi: %h %d", foo, valueOf(SizeOf#(TLPData#(16))));
   endrule
   rule to_bdpi if (can_put_tlp);
      TLPData#(16) foo <- pciehost.pci.request.get;
      put_tlp(foo);
      //$display("to_bdpi");
   endrule
`else
   Clock sys_clk_200mhz <- mkClockIBUFDS(sys_clk_p, sys_clk_n);
   Clock sys_clk_200mhz_buf <- mkClockBUFG(clocked_by sys_clk_200mhz);
   Clock pci_clk_100mhz_buf <- mkClockIBUFDS_GTE2(True, pci_sys_clk_p, pci_sys_clk_n);
   // Instantiate the PCIE endpoint
   PcieEndpointX7#(PcieLanes) ep7 <- mkPcieEndpointX7( clocked_by pci_clk_100mhz_buf
						      , reset_by pci_sys_reset_n
						       );

   Clock epClock125 = ep7.epClock125;
   Reset epReset125 = ep7.epReset125;
   PcieHost#(DataBusWidth, NumberOfMasters) pciehost <- mkPcieHost(
         PciId{ bus:  ep7.cfg.bus_number(), dev: ep7.cfg.device_number(), func: ep7.cfg.function_number()},
         clocked_by epClock125, reset_by epReset125);
   mkConnection(ep7.tlp, pciehost.pci, clocked_by epClock125, reset_by epReset125);
   interface Clock tsys_clk_200mhz = sys_clk_200mhz;
   interface Clock tsys_clk_200mhz_buf = sys_clk_200mhz_buf;
   interface Clock tpci_clk_100mhz_buf = pci_clk_100mhz_buf;
   interface PcieEndpointX7 tep7 = ep7;
`endif
   interface Clock tepClock125 = epClock125;
   interface Reset tepReset125 = epReset125;
   interface PcieHost tpciehost = pciehost;
endmodule

`ifndef BSIM
(* no_default_clock, no_default_reset *)
`endif
module mkPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n, Clock sys_clk_p, Clock sys_clk_n, Reset pci_sys_reset_n)
   (PcieTop#(PinType));

   PcieHostTop host <- mkPcieHostTop(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n);

`ifdef IMPORT_HOSTIF
   let portalTop <- mkSynthesizeablePortalTop(host, clocked_by host.tepClock125, reset_by host.tepReset125);
`else
   let portalTop <- mkSynthesizeablePortalTop(clocked_by host.tepClock125, reset_by host.tepReset125);
`endif
   mkConnection(host.tpciehost.master, portalTop.slave, clocked_by host.tepClock125, reset_by host.tepReset125);
   if (valueOf(NumberOfMasters) > 0) begin
      mapM(uncurry(mkConnection),zip(portalTop.masters, host.tpciehost.slave));
   end

   // going from level to edge-triggered interrupt
   Vector#(15, Reg#(Bool)) interruptRequested <- replicateM(mkReg(False, clocked_by host.tepClock125, reset_by host.tepReset125));
   rule interrupt_rule;
     Integer intr_num = 0;
     for (Integer i = 0; i < 15; i = i + 1) begin
	 if (intr_num == 0 && portalTop.interrupt[i] && !interruptRequested[i])
             intr_num = i+1;
	 interruptRequested[i] <= portalTop.interrupt[i];
     end
     if (intr_num != 0) begin // i= 0 for the directory
        MSIX_Entry msixEntry = host.tpciehost.msixEntry[intr_num];
        host.tpciehost.interruptRequest.put(tuple2({msixEntry.addr_hi, msixEntry.addr_lo}, msixEntry.msg_data));
     end
   endrule

`ifndef BSIM
   interface pcie = host.tep7.pcie;
   method Bit#(NumLeds) leds();
      return extend({host.tep7.user.lnk_up(),3'd2});
   endmethod
   interface pins = portalTop.pins;
`endif
endmodule


Paxos: fix action block in sequence table

// Copyright (c) 2016 Cornell University.

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

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

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

import ClientServer::*;
import DbgTypes::*;
import Ethernet::*;
import FIFO::*;
import GetPut::*;
import MatchTable::*;
import PaxosTypes::*;
import RegFile::*;

interface BasicBlockIncreaseInstance;
   interface BBServer prev_control_state;
endinterface

module mkBasicBlockIncreaseInstance(BasicBlockIncreaseInstance);
   FIFO#(BBRequest) bb_increase_instance_request_fifo <- mkFIFO;
   FIFO#(BBResponse) bb_increase_instance_response_fifo <- mkFIFO;

   rule bb_increase_instance;
      let v <- toGet(bb_increase_instance_request_fifo).get;
      case (v) matches
         tagged BBIncreaseInstanceRequest {pkt: .pkt}: begin
            // read-modify-write register
            BBResponse resp = tagged BBIncreaseInstanceResponse {pkt: pkt};
            bb_increase_instance_response_fifo.enq(resp);
         end
      endcase
   endrule

   interface prev_control_state = (interface BBServer;
      interface request = toPut(bb_increase_instance_request_fifo);
      interface response = toGet(bb_increase_instance_response_fifo);
   endinterface);
endmodule

interface SequenceTable;
   interface BBClient next_control_state_0;
endinterface

module mkSequenceTable#(MetadataClient md)(SequenceTable);
   let verbose = True;

   FIFO#(BBRequest) outReqFifo <- mkFIFO;
   FIFO#(BBResponse) inRespFifo <- mkFIFO;
   FIFO#(PacketInstance) currPacketFifo <- mkFIFO;
   FIFO#(MetadataT) currMetadataFifo <- mkFIFO;

   MatchTable#(256, SequenceTblReqT, SequenceTblRespT) matchTable <- mkMatchTable_256_sequenceTable();

   rule lookup;
      let v <- md.request.get;
      case (v) matches
         tagged SequenceTblRequest { pkt: .pkt, meta: .meta } : begin
            matchTable.lookupPort.request.put(SequenceTblReqT {msgtype: meta.msgtype});
            if (verbose) $display("(%0d) Sequence: %h %h", $time, pkt.id, meta.msgtype);
            currPacketFifo.enq(pkt);
            currMetadataFifo.enq(meta);
         end
      endcase
   endrule

   rule lookup_resp;
      let v <- matchTable.lookupPort.response.get;
      let pkt <- toGet(currPacketFifo).get;
      let meta <- toGet(currMetadataFifo).get;
      if (v matches tagged Valid .resp) begin
         case (resp.act) matches
            IncreaseInstance: begin
               $display("(%0d) increase instance", $time);
               BBRequest req;
               req = tagged BBIncreaseInstanceRequest {pkt: pkt};
               outReqFifo.enq(req);
            end
            default: begin
               $display("(%d) nop", $time);
            end
         endcase
      end
      MetadataResponse resp = tagged SequenceTblResponse {pkt: pkt, meta: meta};
      md.response.put(resp);
   endrule

   rule bb_increase_instance_resp;
      let v <- toGet(inRespFifo).get;
      case (v) matches
         tagged BBIncreaseInstanceResponse {pkt: .pkt}: begin
            $display("(%0d) increase instance: ", $time);
         end
      endcase
   endrule

   interface next_control_state_0 = (interface BBClient;
      interface request = toGet(outReqFifo);
      interface response = toPut(inRespFifo);
   endinterface);
endmodule

// Copyright (c) 2016 Cornell University.

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

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

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

import ClientServer::*;
import DbgTypes::*;
import Ethernet::*;
import FIFO::*;
import GetPut::*;
import PaxosTypes::*;
import RegFile::*;

interface BasicBlockIncreaseInstance;
   interface BBServer prev_control_state;
endinterface

module mkBasicBlockIncreaseInstance(BasicBlockIncreaseInstance);
   FIFO#(BBRequest) bb_increase_instance_request_fifo <- mkFIFO;
   FIFO#(BBResponse) bb_increase_instance_response_fifo <- mkFIFO;

   rule bb_increase_instance;
      let v <- toGet(bb_increase_instance_request_fifo).get;
      case (v) matches
         tagged BBIncreaseInstanceRequest {pkt: .pkt}: begin
            // read-modify-write register
            BBResponse resp = tagged BBIncreaseInstanceResponse {pkt: pkt};
            bb_increase_instance_response_fifo.enq(resp);
         end
      endcase
   endrule

   interface prev_control_state = (interface BBServer;
      interface request = toPut(bb_increase_instance_request_fifo);
      interface response = toGet(bb_increase_instance_response_fifo);
   endinterface);
endmodule

interface SequenceTable;
   interface BBClient next_control_state_0;
endinterface

module mkSequenceTable#(MetadataClient md)(SequenceTable);
   let verbose = True;

   FIFO#(BBRequest) outReqFifo <- mkFIFO;
   FIFO#(BBResponse) inRespFifo <- mkFIFO;
   FIFO#(PacketInstance) currPacketFifo <- mkFIFO;
   FIFO#(MetadataT) currMetadataFifo <- mkFIFO;

   MatchTable#(256, SequenceTblReqT, SequenceTblRespT) matchTable <- mkMatchTable_256_sequenceTable();

   rule lookup;
      let v <- md.request.get;
      case (v) matches
         tagged SequenceTblRequest { pkt: .pkt, meta: .meta } : begin
            matchTable.lookupPort.request.put(SequenceTblReqT {msgtype: meta.msgtype});
            if (verbose) $display("(%0d) Sequence: %h %h", $time, pkt.id, meta.msgtype);
            currPacketFifo.enq(pkt);
            currMetadataFifo.enq(meta);
         end
      endcase
   endrule

   rule lookup_resp;
      let v <- toGet(inRespFifo).get;
      let pkt <- toGet(currPacketFifo).get;
      let meta <- toGet(currMetadataFifo).get;
      if (v matches tagged Valid .resp) begin
         case (resp.act) matches
            IncreaseInstance: begin
               $display("(%0d) increase instance", $time);
               BBRequest req;
               req = tagged BBIncreaseInstanceRequest {pkt: pkt};
               outReqFifo.enq(req);
            end
            default: begin
               $display("(%d) nop", $time);
            end
         endcase
      end
      MetadataResponse resp = tagged SequenceTblResponse {pkt: pkt, meta: meta};
      md.response.put(resp);
   endrule

   interface next_control_state_0 = (interface BBClient;
      interface request = toGet(outReqFifo);
      interface response = toPut(inRespFifo);
   endinterface);
endmodule