added import BVI for XsimMemReadWrite and instances of ModulePareffReadWrite for xsim

// Copyright (c) 2015 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 Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes          :: *;
import Pareff            ::*;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimSource;
    method Action beat(Bit#(32) v);
endinterface
import "BVI" XsimSource =
module mkXsimSourceBVI#(Bit#(32) portal)(XsimSource);
    port portal = portal;
    method beat(beat) enable(en_beat);
endmodule
module mkXsimSource#(PortalMsgIndication indication)(Empty);
   let tmp <- mkXsimSourceBVI(indication.id);
   rule ind_dst_rdy;
      indication.message.deq();
      tmp.beat(indication.message.first());
   endrule
endmodule

interface MsgSinkR#(numeric type bytes_per_beat);
   method Bool src_rdy();
   method Bit#(32) beat();
endinterface

import "BVI" XsimSink =
module mkXsimSinkBVI#(Bit#(32) portal)(MsgSinkR#(4));
    port portal = portal;
    method src_rdy src_rdy();
    method beat beat();
    schedule (src_rdy, beat) CF (src_rdy, beat);
endmodule
module mkXsimSink#(PortalMsgRequest request)(MsgSinkR#(4));
   let sink <- mkXsimSinkBVI(request.id);
   rule req_src_rdy if (sink.src_rdy);
      request.message.enq(sink.beat);
   endrule
endmodule

interface XsimMemReadWrite;
   method Action write32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
   method Action write64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
   method ActionValue#(Bit#(32)) read32(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(64)) read64(Bit#(32) handle, Bit#(32) addr);
endinterface

import "BVI" XsimMemReadWrite =
module mkXsimReadWrite(XsimMemReadWrite);
   method write32(write32_handle, write32_addr, write32_data) enable (en_write32);
   method write64(write64_handle, write64_addr, write64_data) enable (en_write64);
   method read32_data read32(read32_handle, read32_addr) enable (en_read32);
   method read64_data read64(read64_handle, read64_addr) enable (en_read64);
   schedule (write32, write64, read32, read64) CF (write32, write64, read32, read64);
endmodule

instance ModulePareffReadWrite#(32);
   module mkPareffReadWrite(PareffReadWrite#(32) ifc);
      let rw <- mkXsimReadWrite();
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
	  rw.write32(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(32)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- rw.read32(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance ModulePareffReadWrite#(64);
   module mkPareffReadWrite(PareffReadWrite#(64) ifc);
      let rw <- mkXsimReadWrite();
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
	  rw.write64(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(64)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- rw.read64(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance ModulePareffReadWrite#(128);
   module mkPareffReadWrite(PareffReadWrite#(128) ifc);
      let rw <- mkXsimReadWrite();
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(128) v);
	  rw.write64(handle, addr, v[63:0]);
	  rw.write64(handle, addr+8, v[127:64]);
       endmethod
       method ActionValue#(Bit#(128)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v0 <- rw.read64(handle, addr);
	  let v1 <- rw.read64(handle, addr+8);
	  return {v1,v0};
       endmethod
   endmodule
endinstance
instance ModulePareffReadWrite#(256);
   module mkPareffReadWrite(PareffReadWrite#(256) ifc);
      let rw <- mkXsimReadWrite();
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(256) v);
	  rw.write64(handle, addr, v[63:0]);
	  rw.write64(handle, addr+8, v[127:64]);
	  rw.write64(handle, addr+16, v[191:128]);
	  rw.write64(handle, addr+24, v[255:192]);
       endmethod
       method ActionValue#(Bit#(256)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v0 <- rw.read64(handle, addr);
	  let v1 <- rw.read64(handle, addr+8);
	  let v2 <- rw.read64(handle, addr+16);
	  let v3 <- rw.read64(handle, addr+24);
	  return {v3,v2,v1,v0};
       endmethod
   endmodule
endinstance

module mkXsimMemoryConnection#(PhysMemMaster#(addrWidth, dataWidth) master)(Empty)
   provisos (Mul#(TDiv#(dataWidth, 8), 8, dataWidth),
	     ModulePareffReadWrite#(dataWidth));
   PhysMemSlave#(addrWidth,dataWidth) slave <- mkPareffDmaMaster();
   mkConnection(master, slave);
endmodule

module mkXsimTop(Empty);
   Clock derivedClock <- exposeCurrentClock;
   Reset derivedReset <- exposeCurrentReset;

   Reg#(Bool) dumpstarted <- mkReg(False);
   rule startdump if (!dumpstarted);
      //$dumpfile("dump.vcd");
      //$dumpvars;
      dumpstarted <= True;
   endrule
   XsimHost host <- mkXsimHost(derivedClock, derivedReset);
   let top <- mkCnocTop(
`ifdef IMPORT_HOSTIF
       host
`endif
       );
   mapM_(mkXsimSource, top.indications);
   mapM_(mkXsimSink, top.requests);
   mapM_(mkXsimMemoryConnection, top.masters);
endmodule

// Copyright (c) 2015 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 Portal            :: *;
import Top               :: *;
import HostInterface     :: *;
import Pipe::*;
import CnocPortal::*;
import MemTypes          :: *;
import Pareff            ::*;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimSource;
    method Action beat(Bit#(32) v);
endinterface
import "BVI" XsimSource =
module mkXsimSourceBVI#(Bit#(32) portal)(XsimSource);
    port portal = portal;
    method beat(beat) enable(en_beat);
endmodule
module mkXsimSource#(PortalMsgIndication indication)(Empty);
   let tmp <- mkXsimSourceBVI(indication.id);
   rule ind_dst_rdy;
      indication.message.deq();
      tmp.beat(indication.message.first());
   endrule
endmodule

interface MsgSinkR#(numeric type bytes_per_beat);
   method Bool src_rdy();
   method Bit#(32) beat();
endinterface

import "BVI" XsimSink =
module mkXsimSinkBVI#(Bit#(32) portal)(MsgSinkR#(4));
    port portal = portal;
    method src_rdy src_rdy();
    method beat beat();
    schedule (src_rdy, beat) CF (src_rdy, beat);
endmodule
module mkXsimSink#(PortalMsgRequest request)(MsgSinkR#(4));
   let sink <- mkXsimSinkBVI(request.id);
   rule req_src_rdy if (sink.src_rdy);
      request.message.enq(sink.beat);
   endrule
endmodule

module mkXsimMemoryConnection#(PhysMemMaster#(addrWidth, dataWidth) master)(Empty)
   provisos (ModulePareffReadWrite#(dataWidth));
   PhysMemSlave#(addrWidth,dataWidth) slave <- mkPareffDmaMaster();
   mkConnection(master, slave);
endmodule

module mkXsimTop(Empty);
   Clock derivedClock <- exposeCurrentClock;
   Reset derivedReset <- exposeCurrentReset;

   Reg#(Bool) dumpstarted <- mkReg(False);
   rule startdump if (!dumpstarted);
      //$dumpfile("dump.vcd");
      //$dumpvars;
      dumpstarted <= True;
   endrule
   XsimHost host <- mkXsimHost(derivedClock, derivedReset);
   let top <- mkCnocTop(
`ifdef IMPORT_HOSTIF
       host
`endif
       );
   mapM_(mkXsimSource, top.indications);
   mapM_(mkXsimSink, top.requests);
   mapM_(mkXsimMemoryConnection, top.masters);
endmodule


create enum for constants

create enum for constants

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

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

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

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

// types needed by both hardware and software
import GetPutF::*;

interface ServerF#(type intype, type outtype);
	  interface PutF#(intype) request;
	  interface GetF#(outtype) response;
endinterface

typedef enum {
 CmdNOP = 0,
 CmdCOPY = 1,
 CmdECHO = 2
   } OpCode deriving (Bits);

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

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

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

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

// types needed by both hardware and software
import GetPutF::*;

interface ServerF#(type intype, type outtype);
	  interface PutF#(intype) request;
	  interface GetF#(outtype) response;
endinterface

typedef 0 CmdNOP;
typedef 1 CmdCOPY;
typedef 2 CmdECHO;


split requst and indication off from rest of module

import FIFO::*;
import GetPut::*;
import StmtFSM::*;
import TinyTypes::*;
import TinyAsm::*;
import Tiny3::*;
import BRAM::*;

import TinyTestTypes::*;

module mkTiny3Request(Tiny3Indication indication)(Tiny3Request);

   /********** the program we wish to assemble **********/
   function List#(AsmLineT) my_program(function ImmT findaddr(String label)) =
      cons(asmi("",    0, 0), // put 0 in r0
      cons(asmi("",    1, 10), // put 10 in r1
      cons(asmi("",    2, findaddr("loop")), // loop address in r2
      cons(asm("loop", OpOut, FDECb, ShiftNone, SkipNever, 1, 0, 1), // r1-- and output
      cons(asm("",     OpJump, FaORb, ShiftNone, SkipZero, 3, 2, 0), // jump r2 if not zero
      cons(asm("",     OpReserved, Freserved, ShiftNone, SkipNever, 0, 0, 0), // stop processor
      tagged Nil))))));

   InstructionROM_T irom = assembler(my_program);

   TinyCompIfc tiny <- mkTinyComp(irom);

   rule handle_output;
      let out <- tiny.out.get();
      indication.outputdata(out);
      $display("%05t: output = %d\n",$time,out);
   endrule

   method Action inputdata(Bit#(32) v);
      tiny.in(v);
      indication.inputresponse();
   endmethod

endmodule

import FIFO::*;
import GetPut::*;
import StmtFSM::*;
import TinyTypes::*;
import TinyAsm::*;
import Tiny3::*;
import BRAM::*;

interface Tiny3Indication;
   method Action outputdata(Bit#(32) v);
   method Action inputresponse();
endinterface

interface Tiny3Request;
   method Action inputdata(Bit#(32) v);
endinterface

module mkTiny3Request(Tiny3Indication indication)(Tiny3Request);

   /********** the program we wish to assemble **********/
   function List#(AsmLineT) my_program(function ImmT findaddr(String label)) =
      cons(asmi("",    0, 0), // put 0 in r0
      cons(asmi("",    1, 10), // put 10 in r1
      cons(asmi("",    2, findaddr("loop")), // loop address in r2
      cons(asm("loop", OpOut, FDECb, ShiftNone, SkipNever, 1, 0, 1), // r1-- and output
      cons(asm("",     OpJump, FaORb, ShiftNone, SkipZero, 3, 2, 0), // jump r2 if not zero
      cons(asm("",     OpReserved, Freserved, ShiftNone, SkipNever, 0, 0, 0), // stop processor
      tagged Nil))))));

   InstructionROM_T irom = assembler(my_program);

   TinyCompIfc tiny <- mkTinyComp(irom);

   rule handle_output;
      let out <- tiny.out.get();
      indication.outputdata(out);
      $display("%05t: output = %d\n",$time,out);
   endrule

   method Action inputdata(Bit#(32) v);
      tiny.in(v);
      indication.inputresponse();
   endmethod

endmodule


cleanup

cleanup

// 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 FIFOF        :: *;
import Connectable       :: *;
import ClientServer      :: *;
import Xilinx            :: *;
import DefaultValue    :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import PcieGearbox    :: *;
import XbsvXilinx7Pcie   :: *;
import PCIEWRAPPER       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiSlaveEngine    :: *;
import AxiMasterEngine   :: *;
import AxiMasterSlave    :: *;
import AxiDma            :: *;
import AxiCsr            :: *;

import BRAM         :: *;

typedef (function Module#(PortalTop#(40, dsz, ipins,nMasters)) mkPortalTop()) MkPortalTop#(numeric type dsz, type ipins, numeric type nMasters);

`ifdef Artix7
typedef 4 PcieLanes;
typedef 4 NumLeds;
`else
typedef 8 PcieLanes;
typedef 8 NumLeds;
`endif

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

interface PcieHost#(type ipins);
   interface ipins       pins;
endinterface

module [Module] mkPcieHost #(Clock epClock250, Reset epReset250, PciId my_pciId, MkPortalTop#(dsz, ipins, nMasters) mkPortalTop,
Server#(TLPData#(8), TLPData#(8)) ep_tlp)(PcieHost#(ipins))
provisos(
   Mul#(TDiv#(dsz, 8), 8, dsz),
    Add#(a__, TDiv#(dsz, 32), 8),
    Add#(b__, TMul#(32, TDiv#(dsz, 32)), 256),
    Add#(c__, TMul#(8, TDiv#(dsz, 32)), 64),
    Add#(d__, dsz, 256),
    Add#(e__, 32, dsz),
    Mul#(TDiv#(dsz, 32), 32, dsz));
   Clock epClock125 <- exposeCurrentClock();
   Reset epReset125 <- exposeCurrentReset();
   MakeResetIfc portalResetIfc <- mkReset(10, False, epClock125);
   let portalTop <- mkPortalTop(reset_by portalResetIfc.new_rst);

   PcieTracer      traceif <- mkPcieTracer();
   // The PCIE endpoint is processing TLPData#(8)s at 250MHz.  The
   // AXI bridge is accepting TLPData#(16)s at 125 MHz. The
   // connection between the endpoint and the AXI contains GearBox
   // instances for the TLPData#(8)@250 <--> TLPData#(16)@125
   // conversion.
   PcieGearbox gb <- mkPcieGearbox(epClock250, epReset250, epClock125, epReset125);
   mkConnection(gb.tlp, ep_tlp, clocked_by epClock250, reset_by epReset250);
   mkConnection(gb.pci, traceif.pci);

   TLPDispatcher   dispatcher <- mkTLPDispatcher();
   TLPArbiter      arbiter    <- mkTLPArbiter();
   AxiMasterEngine splitMaster     <- mkAxiMasterEngine(my_pciId);
   AxiControlAndStatusRegs csr     <- mkAxiControlAndStatusRegs(portalResetIfc, traceif.tlp);
   mkConnection(splitMaster.master, csr.slave);
   mkConnection(
       (interface Server;
          interface response = dispatcher.outToConfig;
          interface request = arbiter.inFromConfig;
       endinterface), splitMaster.tlp);

   mkConnection(traceif.bus,
       (interface Client;
          interface request = arbiter.outToBus;
          interface response = dispatcher.inFromBus;
       endinterface));

   // Build the PCIe-to-AXI bridge
   AxiSlaveEngine#(dsz) dmaEngine <- mkAxiSlaveEngine(my_pciId);
   Vector#(nMasters,Axi3Master#(40,dsz,6)) m_axis;
   mkConnection(
       (interface Server;
          interface response = dispatcher.outToAxi;
          interface request = arbiter.inFromAxi;
       endinterface), dmaEngine.pci);
   if(valueOf(nMasters) > 0) begin
      m_axis[0] <- mkAxiDmaMaster(portalTop.masters[0], reset_by portalResetIfc.new_rst);
      mkConnection(m_axis[0], dmaEngine.slave);
   end

   AxiMasterEngine portalEngine <- mkAxiMasterEngine(my_pciId);
   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(portalTop.slave);
   mkConnection(
       (interface Server;
          interface response = dispatcher.outToPortal;
          interface request = arbiter.inFromPortal;
       endinterface), portalEngine.tlp);
   mkConnection(portalEngine.master, ctrl);

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

   interface pins = portalTop.pins;
endmodule: mkPcieHost

(* no_default_clock, no_default_reset *)
module [Module] mkPcieTopFromPortal #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
				      Clock sys_clk_p,     Clock sys_clk_n,
				      Reset pci_sys_reset_n,
				      MkPortalTop#(dsz, ipins, nMasters) mkPortalTop)
   (PcieTop#(ipins))
   provisos (Mul#(TDiv#(dsz, 32), 32, dsz),
	     Add#(b__, 32, dsz),
	     Add#(c__, dsz, 256),
	     Add#(d__, TMul#(8, TDiv#(dsz, 32)), 64),
	     Add#(e__, TMul#(32, TDiv#(dsz, 32)), 256),
	     Add#(f__, TDiv#(dsz, 32), 8),
	     Mul#(TDiv#(dsz, 8), 8, dsz),
	     Add#(g__, nMasters, 1)
      );

   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
   PCIExpressX7#(PcieLanes) _ep <- mkPCIExpressEndpointX7( defaultValue
						  , clocked_by pci_clk_100mhz_buf
						  , reset_by pci_sys_reset_n
						  );
   // The PCIe endpoint exports full (250MHz) and half-speed (125MHz) clocks
   Clock epClock250 = _ep.user.clk_out;
   Reset user_reset_n <- mkResetInverter(_ep.user.reset_out);
   Reset epReset250 <- mkAsyncReset(4, user_reset_n, epClock250);

   ClockGenerator7Params     params = defaultValue;
   params.clkin1_period    = 4.000;
   params.clkin_buffer     = False;
   params.clkfbout_mult_f  = 4.000;
   params.clkout0_divide_f = 8.000;
   ClockGenerator7           clkgen <- mkClockGenerator7(params, clocked_by _ep.user.clk_out, reset_by user_reset_n);
   Clock epClock125 = clkgen.clkout0; /* half speed user_clk */
   Reset epReset125 <- mkAsyncReset(4, user_reset_n, epClock125);

   PcieHost#(ipins) pciehost <- mkPcieHost(epClock250, epReset250,
         PciId{ bus:  _ep.cfg.bus_number(), dev: _ep.cfg.device_number(), func: _ep.cfg.function_number()},
         mkPortalTop, _ep.tlp, clocked_by epClock125, reset_by epReset125);

   interface pcie = _ep.pcie;
   method Bit#(NumLeds) leds();
      return extend({_ep.user.lnk_up(),3'd2});
   endmethod
   interface pins = pciehost.pins;

endmodule: mkPcieTopFromPortal

`ifndef DataBusWidth
`define DataBusWidth 64
`endif
`ifndef NumberOfMasters
`define NumberOfMasters 1
`endif
(* synthesize *)
module mkSynthesizeablePortalTop(PortalTop#(40, `DataBusWidth, Empty, `NumberOfMasters));
   let top <- mkPortalTop();
   interface masters = top.masters;
   interface slave = top.slave;
   interface interrupt = top.interrupt;
   interface leds = top.leds;
   interface pins = top.pins;
endmodule

`ifndef PinType
`define PinType Empty
`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));
   let top <- mkPcieTopFromPortal(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,mkSynthesizeablePortalTop);
   return top;
endmodule: mkPcieTop

// 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 FIFOF        :: *;
import Connectable       :: *;
import ClientServer      :: *;
import Xilinx            :: *;
import DefaultValue    :: *;
import PcieSplitter      :: *;
import PcieTracer        :: *;
import PcieGearbox    :: *;
import XbsvXilinx7Pcie   :: *;
import PCIEWRAPPER       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiSlaveEngine    :: *;
import AxiMasterEngine   :: *;
import AxiMasterSlave    :: *;
import AxiDma            :: *;
import AxiCsr            :: *;

import BRAM         :: *;

typedef (function Module#(PortalTop#(40, dsz, ipins,nMasters)) mkPortalTop()) MkPortalTop#(numeric type dsz, type ipins, numeric type nMasters);

`ifdef Artix7
typedef 4 PcieLanes;
typedef 4 NumLeds;
`else
typedef 8 PcieLanes;
typedef 8 NumLeds;
`endif

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

interface PcieHost#(type ipins);
   interface ipins       pins;
endinterface

module [Module] mkPcieHost #(Clock epClock250, Reset epReset250, PciId my_pciId, MkPortalTop#(dsz, ipins, nMasters) mkPortalTop,
Server#(TLPData#(8), TLPData#(8)) ep_tlp)(PcieHost#(ipins))
provisos(
   Mul#(TDiv#(dsz, 8), 8, dsz),
    Add#(a__, TDiv#(dsz, 32), 8),
    Add#(b__, TMul#(32, TDiv#(dsz, 32)), 256),
    Add#(c__, TMul#(8, TDiv#(dsz, 32)), 64),
    Add#(d__, dsz, 256),
    Add#(e__, 32, dsz),
    Mul#(TDiv#(dsz, 32), 32, dsz));
   Clock epClock125 <- exposeCurrentClock();
   Reset epReset125 <- exposeCurrentReset();
   MakeResetIfc portalResetIfc <- mkReset(10, False, epClock125);
   TLPDispatcher        dispatcher <- mkTLPDispatcher();
   TLPArbiter           arbiter    <- mkTLPArbiter();
   PcieTracer  traceif <- mkPcieTracer();
   AxiControlAndStatusRegs csr     <- mkAxiControlAndStatusRegs(portalResetIfc, traceif.tlp);
   AxiMasterEngine splitMaster     <- mkAxiMasterEngine(my_pciId);
   mkConnection(splitMaster.master, csr.slave);
   mkConnection(
       (interface Server;
          interface response = dispatcher.outToConfig;
          interface request = arbiter.inFromConfig;
       endinterface), splitMaster.tlp);

   mkConnection(traceif.bus,
       (interface Client;
          interface request = arbiter.outToBus;
          interface response = dispatcher.inFromBus;
       endinterface));

   // The PCIE endpoint is processing TLPData#(8)s at 250MHz.  The
   // AXI bridge is accepting TLPData#(16)s at 125 MHz. The
   // connection between the endpoint and the AXI contains GearBox
   // instances for the TLPData#(8)@250 <--> TLPData#(16)@125
   // conversion.
   PcieGearbox gb <- mkPcieGearbox(epClock250, epReset250, epClock125, epReset125);
   mkConnection(gb.tlp, ep_tlp, clocked_by epClock250, reset_by epReset250);
   mkConnection(gb.pci, traceif.pci);

   // instantiate user portals
   let portalTop <- mkPortalTop(reset_by portalResetIfc.new_rst);
   AxiSlaveEngine#(dsz) axiSlaveEngine <- mkAxiSlaveEngine(my_pciId);
   AxiMasterEngine axiMasterEngine <- mkAxiMasterEngine(my_pciId);

   // Build the PCIe-to-AXI bridge
   mkConnection(
       (interface Server;
          interface response = dispatcher.outToAxi;
          interface request = arbiter.inFromAxi;
       endinterface), axiSlaveEngine.pci);
   Vector#(nMasters,Axi3Master#(40,dsz,6)) m_axis;
   if(valueOf(nMasters) > 0) begin
      m_axis[0] <- mkAxiDmaMaster(portalTop.masters[0], reset_by portalResetIfc.new_rst);
      mkConnection(m_axis[0], axiSlaveEngine.slave);
   end
   mkConnection(
       (interface Server;
          interface response = dispatcher.outToPortal;
          interface request = arbiter.inFromPortal;
       endinterface), axiMasterEngine.tlp);

   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(portalTop.slave);
   mkConnection(axiMasterEngine.master, ctrl);

   // going from level to edge-triggered interrupt
   Vector#(15, Reg#(Bool)) interruptRequested <- replicateM(mkReg(False));
   for (Integer i = 0; i < 15; i = i + 1) begin
      // intr_num 0 for the directory
      Integer intr_num = i+1;
      MSIX_Entry msixEntry = csr.msixEntry[intr_num];
      rule interruptRequest;
	 if (portalTop.interrupt[i] && !interruptRequested[i])
	    axiMasterEngine.interruptRequest.put(tuple2({msixEntry.addr_hi, msixEntry.addr_lo}, msixEntry.msg_data));
	 interruptRequested[i] <= portalTop.interrupt[i];
      endrule
   end
   interface pins = portalTop.pins;
endmodule: mkPcieHost

(* no_default_clock, no_default_reset *)
module [Module] mkPcieTopFromPortal #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
				      Clock sys_clk_p,     Clock sys_clk_n,
				      Reset pci_sys_reset_n,
				      MkPortalTop#(dsz, ipins, nMasters) mkPortalTop)
   (PcieTop#(ipins))
   provisos (Mul#(TDiv#(dsz, 32), 32, dsz),
	     Add#(b__, 32, dsz),
	     Add#(c__, dsz, 256),
	     Add#(d__, TMul#(8, TDiv#(dsz, 32)), 64),
	     Add#(e__, TMul#(32, TDiv#(dsz, 32)), 256),
	     Add#(f__, TDiv#(dsz, 32), 8),
	     Mul#(TDiv#(dsz, 8), 8, dsz),
	     Add#(g__, nMasters, 1)
      );

   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
   PCIExpressX7#(PcieLanes) _ep <- mkPCIExpressEndpointX7( defaultValue
						  , clocked_by pci_clk_100mhz_buf
						  , reset_by pci_sys_reset_n
						  );
   // The PCIe endpoint exports full (250MHz) and half-speed (125MHz) clocks
   Clock epClock250 = _ep.user.clk_out;
   Reset user_reset_n <- mkResetInverter(_ep.user.reset_out);
   Reset epReset250 <- mkAsyncReset(4, user_reset_n, epClock250);

   ClockGenerator7Params     params = defaultValue;
   params.clkin1_period    = 4.000;
   params.clkin_buffer     = False;
   params.clkfbout_mult_f  = 4.000;
   params.clkout0_divide_f = 8.000;
   ClockGenerator7           clkgen <- mkClockGenerator7(params, clocked_by _ep.user.clk_out, reset_by user_reset_n);
   Clock epClock125 = clkgen.clkout0; /* half speed user_clk */
   Reset epReset125 <- mkAsyncReset(4, user_reset_n, epClock125);

   PcieHost#(ipins) pciehost <- mkPcieHost(epClock250, epReset250,
         PciId{ bus:  _ep.cfg.bus_number(), dev: _ep.cfg.device_number(), func: _ep.cfg.function_number()},
         mkPortalTop, _ep.tlp, clocked_by epClock125, reset_by epReset125);

   interface pcie = _ep.pcie;
   method Bit#(NumLeds) leds();
      return extend({_ep.user.lnk_up(),3'd2});
   endmethod
   interface pins = pciehost.pins;

endmodule: mkPcieTopFromPortal

`ifndef DataBusWidth
`define DataBusWidth 64
`endif
`ifndef NumberOfMasters
`define NumberOfMasters 1
`endif
(* synthesize *)
module mkSynthesizeablePortalTop(PortalTop#(40, `DataBusWidth, Empty, `NumberOfMasters));
   let top <- mkPortalTop();
   interface masters = top.masters;
   interface slave = top.slave;
   interface interrupt = top.interrupt;
   interface leds = top.leds;
   interface pins = top.pins;
endmodule

`ifndef PinType
`define PinType Empty
`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));
   let top <- mkPcieTopFromPortal(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,mkSynthesizeablePortalTop);
   return top;
endmodule: mkPcieTop


clean up

clean up

`ifdef DEPARSER_STRUCT
typedef enum {
    StateDeparseStart,
    StateDeparseEthernet,
    StateDeparseIpv4,
    StateDeparseUdp,
    StateDeparseHeader0,
    StateDeparseTcp
} DeparserState deriving (Bits, Eq, FShow);
`endif  // DEPARSER_STRUCT
`ifdef DEPARSER_RULES
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_ethernet, StateDeparseEthernet, 112))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseEthernet, 112))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseEthernet, 112))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_ipv4, StateDeparseIpv4, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseIpv4, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseIpv4, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_udp, StateDeparseUdp, 64))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseUdp, 64))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseUdp, 64))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_header_0, StateDeparseHeader0, 256))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseHeader0, 256))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseHeader0, 256))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_tcp, StateDeparseTcp, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseTcp, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseTcp, 160))));
Vector#(15, Rules) fsmRules = toVector(deparse_fsm);
`endif  // DEPARSER_RULES
`ifdef DEPARSER_STATE
PulseWire w_ethernet <- mkPulseWire();
PulseWire w_ipv4 <- mkPulseWire();
PulseWire w_udp <- mkPulseWire();
PulseWire w_header_0 <- mkPulseWire();
PulseWire w_tcp <- mkPulseWire();

function Bit#(6) nextDeparseState(MetadataT metadata);
    Vector#(6, Bool) headerValid;
    headerValid[0] = False;
    headerValid[1] = checkForward(metadata.hdr.ethernet);
    headerValid[2] = checkForward(metadata.hdr.ipv4);
    headerValid[3] = checkForward(metadata.hdr.udp);
    headerValid[4] = checkForward(metadata.hdr.header_0);
    headerValid[5] = checkForward(metadata.hdr.tcp);
    let vec = pack(headerValid);
    return vec;
endfunction

function Action transit_next_state(MetadataT metadata);
    action
    let vec = nextDeparseState(metadata);
    if (vec == 0) begin
        header_done <= True;
    end
    else begin
        Bit#(3) nextHeader = truncate(pack(countZerosLSB(vec)% 6));
        DeparserState nextState = unpack(nextHeader);
        case (nextState) matches
            StateDeparseEthernet: w_ethernet.send();
            StateDeparseIpv4: w_ipv4.send();
            StateDeparseUdp: w_udp.send();
            StateDeparseHeader0: w_header_0.send();
            StateDeparseTcp: w_tcp.send();
            default: $display("ERROR: unknown states.");
        endcase
    end
    endaction
endfunction
function MetadataT update_metadata(DeparserState state);
    let metadata = rg_metadata;
    case (state) matches
        StateDeparseEthernet :
            metadata.hdr.ethernet = updateState(metadata.hdr.ethernet, tagged StructDefines::NotPresent);
        StateDeparseIpv4 :
            metadata.hdr.ipv4 = updateState(metadata.hdr.ipv4, tagged StructDefines::NotPresent);
        StateDeparseUdp :
            metadata.hdr.udp = updateState(metadata.hdr.udp, tagged StructDefines::NotPresent);
        StateDeparseHeader0 :
            metadata.hdr.header_0 = updateState(metadata.hdr.header_0, tagged StructDefines::NotPresent);
        StateDeparseTcp :
            metadata.hdr.tcp = updateState(metadata.hdr.tcp, tagged StructDefines::NotPresent);
    endcase
    return metadata;
endfunction
let initState = StateDeparseEthernet;
`endif  // DEPARSER_STATE

`ifdef DEPARSER_STRUCT
typedef enum {
    StateDeparseStart,
    StateDeparseEthernet,
    StateDeparseIpv4,
    StateDeparseUdp,
    StateDeparseHeader0,
    StateDeparseTcp
} DeparserState deriving (Bits, Eq, FShow);
`endif  // DEPARSER_STRUCT
`ifdef DEPARSER_RULES
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_ethernet, StateDeparseEthernet, 112))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseEthernet, 112))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseEthernet, 112))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_ipv4, StateDeparseIpv4, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseIpv4, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseIpv4, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_udp, StateDeparseUdp, 64))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseUdp, 64))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseUdp, 64))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_header_0, StateDeparseHeader0, 256))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseHeader0, 256))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseHeader0, 256))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_tcp, StateDeparseTcp, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparseTcp, 160))));
`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparseTcp, 160))));
Vector#(15, Rules) fsmRules = toVector(deparse_fsm);
`endif  // DEPARSER_RULES
`ifdef DEPARSER_STATE
PulseWire w_ethernet <- mkPulseWire();
PulseWire w_ipv4 <- mkPulseWire();
PulseWire w_udp <- mkPulseWire();
PulseWire w_header_0 <- mkPulseWire();
PulseWire w_tcp <- mkPulseWire();

function Bit#(6) nextDeparseState(MetadataT metadata);
    Vector#(6, Bool) headerValid;
    headerValid[0] = False;
    headerValid[1] = checkForward(metadata.hdr.ethernet);
    headerValid[2] = checkForward(metadata.hdr.ipv4);
    headerValid[3] = checkForward(metadata.hdr.udp);
    headerValid[4] = checkForward(metadata.hdr.header_0);
    headerValid[5] = checkForward(metadata.hdr.tcp);
    let vec = pack(headerValid);
    return vec;
endfunction

function Action transit_next_state(MetadataT metadata);
    action
    let vec = nextDeparseState(metadata);
    if (vec == 0) begin
        w_deparse_header_done.send();
    end
    else begin
        Bit#(3) nextHeader = truncate(pack(countZerosLSB(vec)% 6));
        DeparserState nextState = unpack(nextHeader);
        case (nextState) matches
            StateDeparseEthernet: w_ethernet.send();
            StateDeparseIpv4: w_ipv4.send();
            StateDeparseUdp: w_udp.send();
            StateDeparseHeader0: w_header_0.send();
            StateDeparseTcp: w_tcp.send();
            default: $display("ERROR: unknown states.");
        endcase
    end
    endaction
endfunction
function MetadataT update_metadata(DeparserState state);
    let metadata = meta[0];
    case (state) matches
        StateDeparseEthernet :
            metadata.hdr.ethernet = updateState(metadata.hdr.ethernet, tagged StructDefines::NotPresent);
        StateDeparseIpv4 :
            metadata.hdr.ipv4 = updateState(metadata.hdr.ipv4, tagged StructDefines::NotPresent);
        StateDeparseUdp :
            metadata.hdr.udp = updateState(metadata.hdr.udp, tagged StructDefines::NotPresent);
        StateDeparseHeader0 :
            metadata.hdr.header_0 = updateState(metadata.hdr.header_0, tagged StructDefines::NotPresent);
        StateDeparseTcp :
            metadata.hdr.tcp = updateState(metadata.hdr.tcp, tagged StructDefines::NotPresent);
    endcase
    return metadata;
endfunction
let initState = StateDeparseEthernet;
`endif  // DEPARSER_STATE


tieoff used output queue to ground

tieoff used output queue to ground

// 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.

package Runtime;

import Library::*;
import RxChannel::*;
import TxChannel::*;
import HostChannel::*;
import StreamChannel::*;
import Channel::*;
import Gearbox::*;
import SharedBuff::*;
import PacketBuffer::*;
import Printf::*;
import Stream::*;
import StreamGearbox::*;
import XBar::*;
import SynthBuilder::*;
`include "ConnectalProjectConfig.bsv"
`include "Debug.defines"
`include "TieOff.defines"
`include "SynthBuilder.defines"
`TIEOFF_PIPEOUT("runtime stream ", MetadataRequest)

typedef 512 DatapathWidth;
typedef TDiv#(DatapathWidth, ChannelWidth) BusRatio;

// FIXME: make this right
function Bit#(32) destOf (ByteStream#(64) x);
   // return egress_port in metadata
   return x.user;
   //return 2; //truncate(pack (x.data)) & 'hF;
endfunction

/*
   P4FPGA runtime consists of 5 types of channels and optional packet memory to acclerate packet re-entry

   Streaming-based datapath pipeline
   -> hostchan + rxchan
   -> per channel fifo
   -> per channel deparser (modifier)
   -> crossbar
   -> txchan : gearbox 512 -> 256 -> 128 -> ring to mac
 */
interface Runtime#(numeric type nrx, numeric type ntx, numeric type nhs);
   interface Vector#(nrx, StreamRxChannel) rxchan;
   interface Vector#(nhs, StreamInChannel) hostchan;
   interface Vector#(ntx, TxChannel) txchan;
   // TODO: reentryChannel and dropChannel
   interface Vector#(TAdd#(nrx, nhs), PipeIn#(MetadataRequest)) prev;
   method Action set_verbosity (int verbosity);
endinterface

module mkRuntime#(Clock rxClock, Reset rxReset, Clock txClock, Reset txReset)(Runtime#(nrx, ntx, nhs))
   provisos(Add#(ntx, a__, 8) // FIXME: make ntx == 8, caused by take()
           ,Add#(TAdd#(nrx, nhs), b__, 8) // introduced by take()
           ,NumAlias#(TAdd#(nrx, nhs), npi)
           ,NumAlias#(nhs, rx_offset)
           );

   Vector#(npi, FIFOF#(MetadataRequest)) meta_ff <- replicateM(mkFIFOF);
   function PipeIn#(MetadataRequest) metaPipeIn(Integer i);
      return toPipeIn(meta_ff[i]);
   endfunction
   function PipeOut#(MetadataRequest) metaPipeOut(Integer i);
      return toPipeOut(meta_ff[i]);
   endfunction

   `PRINT_DEBUG_MSG

   function Put#(ByteStream#(64)) get_write_data(PacketBuffer#(64) buff);
      return buff.writeServer.writeData;
   endfunction

   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();

   function Integer add_base (Integer j) = (valueOf(nhs) + j);
   Vector#(nhs, StreamInChannel) _hostchan <- genWithM(mkStreamInChannel);
   Vector#(nrx, StreamRxChannel) _rxchan <- genWithM(compose(mkStreamRxChannel(rxClock, rxReset), add_base));
   Vector#(npi, StreamOutChannel) _streamchan <- genWithM(mkStreamOutChannel());
   Vector#(ntx, TxChannel) _txchan <- replicateM(mkTxChannel(txClock, txReset));

   // processed metadata to stream pipeline
   // mapM_(mkTieOff, map(toPipeOut, meta_ff));
   mapM_(uncurry(mkConnection), zip(genWith(metaPipeOut), map(getMetaIn, _streamchan)));

   // drop streamed bytes on the floor
   // mkTieOff(_hostchan[0].writeClient.writeData);

   Vector#(npi, StreamGearbox#(16, 32)) gearbox_up_16 <- replicateM(mkStreamGearboxUp());
   Vector#(npi, StreamGearbox#(32, 64)) gearbox_up_32 <- replicateM(mkStreamGearboxUp());
   let write_clients = append(map(getWriteClient, _hostchan), map(getWriteClient, _rxchan));
   mapM(uncurry(mkConnection), zip(write_clients, map(getWriteServer, _streamchan)));
   mapM(uncurry(mkConnection), zip(map(getWriteClient, _streamchan), map(getDataIn, gearbox_up_16)));
   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_up_16), map(getDataIn, gearbox_up_32)));

   // DEBUG: sink after gearbox_up_32
   //mapM_(mkTieOff, map(getDataOut, gearbox_up_32));

   Vector#(npi, PacketBuffer#(64)) input_queues <- mapM(mkPacketBuffer, genWith(sprintf("inputQ %h"))); // input queue
   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_up_32), map(getWriteData, input_queues))); // gearbox -> input queue
   mapM(uncurry(mkConnection), zip(map(getReadLen, input_queues), map(getReadReq, input_queues))); // immediate transmit, performance issue?

   XBar#(64) xbar <- mkXBar(3, destOf, mkMerge2x1_lru, 3, 0); // last two parameters are log(size) and idx
   Vector#(8, Put#(ByteStream#(64))) input_ports = toVector(xbar.input_ports);
   mapM(uncurry(mkConnection), zip(map(getReadData, input_queues), take(input_ports))); // input queue -> xbar,

   Vector#(8, PacketBuffer#(64)) output_queues <- mapM(mkPacketBuffer, genWith(sprintf("outputQ %h"))); // output queue
   mapM(uncurry(mkConnection), zip(map(getReadLen, output_queues), map(getReadReq, output_queues))); // immediate transmit

   Vector#(8, Get#(ByteStream#(64))) outvec = toVector(xbar.output_ports);
   Vector#(ntx, StreamGearbox#(64, 32)) gearbox_dn_32 <- replicateM(mkStreamGearboxDn());
   Vector#(ntx, StreamGearbox#(32, 16)) gearbox_dn_16 <- replicateM(mkStreamGearboxDn());
   //mapM_(mkTieOff, outvec); // want to see which idx is going out of
   mapM(uncurry(mkConnection), zip(outvec, map(get_write_data, output_queues))); // xbar -> output queue
   mapM(uncurry(mkConnection), zip(map(getReadData, takeAt(`NUM_HOSTCHAN, output_queues)), map(getDataIn, gearbox_dn_32))); // output queue -> gearbox

   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_dn_32), map(getDataIn, gearbox_dn_16)));
   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_dn_16), map(getWriteServer, _txchan)));

   // forward packet to any of these ports will be dropped
   mkTieOff(output_queues[0].readServer.readData);
   mkTieOff(output_queues[5].readServer.readData);
   mkTieOff(output_queues[6].readServer.readData);
   mkTieOff(output_queues[7].readServer.readData);

   interface prev = genWith(metaPipeIn); // metadata in
   interface rxchan = _rxchan;
   interface txchan = _txchan;
   interface hostchan = _hostchan;
   method Action set_verbosity (int verbosity);
      cf_verbosity <= verbosity;
      mapM_(uncurry(set_verbosity), zip(_rxchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(_streamchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(_txchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(_hostchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(input_queues, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(output_queues, replicate(verbosity)));
   endmethod
endmodule

`SynthBuildModule4(mkRuntime, Clock, Reset, Clock, Reset, Runtime#(4, 4, 1), mkRuntime_4_4_1)
endpackage

// 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.

package Runtime;

import Library::*;
import RxChannel::*;
import TxChannel::*;
import HostChannel::*;
import StreamChannel::*;
import Channel::*;
import Gearbox::*;
import SharedBuff::*;
import PacketBuffer::*;
import Printf::*;
import Stream::*;
import StreamGearbox::*;
import XBar::*;
`include "ConnectalProjectConfig.bsv"
`include "Debug.defines"
`include "TieOff.defines"
`TIEOFF_PIPEOUT("runtime stream ", MetadataRequest)

typedef 512 DatapathWidth;
typedef TDiv#(DatapathWidth, ChannelWidth) BusRatio;

// FIXME: make this right
function Bit#(32) destOf (ByteStream#(64) x);
   // return egress_port in metadata
   return x.user;
   //return 2; //truncate(pack (x.data)) & 'hF;
endfunction

/*
   P4FPGA runtime consists of 5 types of channels and optional packet memory to acclerate packet re-entry

   Streaming-based datapath pipeline
   -> hostchan + rxchan
   -> per channel fifo
   -> per channel deparser (modifier)
   -> crossbar
   -> txchan : gearbox 512 -> 256 -> 128 -> ring to mac
 */
interface Runtime#(numeric type nrx, numeric type ntx, numeric type nhs);
   interface Vector#(nrx, StreamRxChannel) rxchan;
   interface Vector#(nhs, StreamInChannel) hostchan;
   interface Vector#(ntx, TxChannel) txchan;
   // TODO: reentryChannel and dropChannel
   interface Vector#(TAdd#(nrx, nhs), PipeIn#(MetadataRequest)) prev;
   method Action set_verbosity (int verbosity);
endinterface

module mkRuntime#(Clock rxClock, Reset rxReset, Clock txClock, Reset txReset)(Runtime#(nrx, ntx, nhs))
   provisos(Add#(ntx, a__, 8) // FIXME: make ntx == 8, caused by take()
           ,Add#(TAdd#(nrx, nhs), b__, 8) // introduced by take()
           ,NumAlias#(TAdd#(nrx, nhs), npi)
           ,NumAlias#(nhs, rx_offset)
           );

   Vector#(npi, FIFOF#(MetadataRequest)) meta_ff <- replicateM(mkFIFOF);
   function PipeIn#(MetadataRequest) metaPipeIn(Integer i);
      return toPipeIn(meta_ff[i]);
   endfunction
   function PipeOut#(MetadataRequest) metaPipeOut(Integer i);
      return toPipeOut(meta_ff[i]);
   endfunction

   `PRINT_DEBUG_MSG

   function Put#(ByteStream#(64)) get_write_data(PacketBuffer#(64) buff);
      return buff.writeServer.writeData;
   endfunction

   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();

   function Integer add_base (Integer j) = (valueOf(nhs) + j);
   Vector#(nhs, StreamInChannel) _hostchan <- genWithM(mkStreamInChannel);
   Vector#(nrx, StreamRxChannel) _rxchan <- genWithM(compose(mkStreamRxChannel(rxClock, rxReset), add_base));
   Vector#(npi, StreamOutChannel) _streamchan <- genWithM(mkStreamOutChannel());
   Vector#(ntx, TxChannel) _txchan <- replicateM(mkTxChannel(txClock, txReset));

   // processed metadata to stream pipeline
   // mapM_(mkTieOff, map(toPipeOut, meta_ff));
   mapM_(uncurry(mkConnection), zip(genWith(metaPipeOut), map(getMetaIn, _streamchan)));

   // drop streamed bytes on the floor
   // mkTieOff(_hostchan[0].writeClient.writeData);

   Vector#(npi, StreamGearbox#(16, 32)) gearbox_up_16 <- replicateM(mkStreamGearboxUp());
   Vector#(npi, StreamGearbox#(32, 64)) gearbox_up_32 <- replicateM(mkStreamGearboxUp());
   let write_clients = append(map(getWriteClient, _hostchan), map(getWriteClient, _rxchan));
   mapM(uncurry(mkConnection), zip(write_clients, map(getWriteServer, _streamchan)));
   mapM(uncurry(mkConnection), zip(map(getWriteClient, _streamchan), map(getDataIn, gearbox_up_16)));
   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_up_16), map(getDataIn, gearbox_up_32)));

   // DEBUG: sink after gearbox_up_32
   //mapM_(mkTieOff, map(getDataOut, gearbox_up_32));

   Vector#(npi, PacketBuffer#(64)) input_queues <- mapM(mkPacketBuffer, genWith(sprintf("inputQ %h"))); // input queue
   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_up_32), map(getWriteData, input_queues))); // gearbox -> input queue
   mapM(uncurry(mkConnection), zip(map(getReadLen, input_queues), map(getReadReq, input_queues))); // immediate transmit, performance issue?

   XBar#(64) xbar <- mkXBar(3, destOf, mkMerge2x1_lru, 3, 0); // last two parameters are log(size) and idx
   Vector#(8, Put#(ByteStream#(64))) input_ports = toVector(xbar.input_ports);
   mapM(uncurry(mkConnection), zip(map(getReadData, input_queues), take(input_ports))); // input queue -> xbar,

   Vector#(8, PacketBuffer#(64)) output_queues <- mapM(mkPacketBuffer, genWith(sprintf("outputQ %h"))); // output queue
   mapM(uncurry(mkConnection), zip(map(getReadLen, output_queues), map(getReadReq, output_queues))); // immediate transmit

   Vector#(8, Get#(ByteStream#(64))) outvec = toVector(xbar.output_ports);
   Vector#(ntx, StreamGearbox#(64, 32)) gearbox_dn_32 <- replicateM(mkStreamGearboxDn());
   Vector#(ntx, StreamGearbox#(32, 16)) gearbox_dn_16 <- replicateM(mkStreamGearboxDn());
   //mapM_(mkTieOff, outvec); // want to see which idx is going out of
   mapM(uncurry(mkConnection), zip(outvec, map(get_write_data, output_queues))); // xbar -> output queue
   mapM(uncurry(mkConnection), zip(map(getReadData, takeAt(`NUM_HOSTCHAN, output_queues)), map(getDataIn, gearbox_dn_32))); // output queue -> gearbox

   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_dn_32), map(getDataIn, gearbox_dn_16)));
   mapM(uncurry(mkConnection), zip(map(getDataOut, gearbox_dn_16), map(getWriteServer, _txchan)));

   interface prev = genWith(metaPipeIn); // metadata in
   interface rxchan = _rxchan;
   interface txchan = _txchan;
   interface hostchan = _hostchan;
   method Action set_verbosity (int verbosity);
      cf_verbosity <= verbosity;
      mapM_(uncurry(set_verbosity), zip(_rxchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(_streamchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(_txchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(_hostchan, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(input_queues, replicate(verbosity)));
      mapM_(uncurry(set_verbosity), zip(output_queues, replicate(verbosity)));
   endmethod
endmodule

endpackage


6 -> ObjectTagSize

6 -> ObjectTagSize

Change-Id: Ic40730e38a79229da3ef9305e7b16cab4a9f3369

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

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

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

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

import BRAM::*;
import FIFO::*;
import Vector::*;
import Gearbox::*;
import FIFOF::*;
import SpecialFIFOs::*;

import BRAMFIFOFLevel::*;
import GetPut::*;
import Dma::*;

function ObjectReadClient#(dataWidth) orc(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaClient;
function ObjectWriteClient#(dataWidth) owc(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaClient;
function ObjectReadServer#(dataWidth) ors(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaServer;
function ObjectWriteServer#(dataWidth) ows(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaServer;

//
// @brief A buffer for reading from a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaReadBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectReadServer #(dataWidth) dmaServer;
   interface ObjectReadClient#(dataWidth) dmaClient;
endinterface

//
// @brief A buffer for writing to a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaWriteBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectWriteServer#(dataWidth) dmaServer;
   interface ObjectWriteClient#(dataWidth) dmaClient;
endinterface

//
// @brief Makes a Dma buffer for reading wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaReadBuffer(DmaReadBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1,TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth))  readBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableBuffers <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      Bool ready = (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableBuffers.read());
      if (ready) begin
	 hasEnoughCapacity.enq(True);
      end
   endrule

   // only issue the readRequest when sufficient buffering is available.  This includes the buffering we have already committed.
   interface ObjectReadServer dmaServer;
      interface Put readReq = toPut(reqOutstanding);
      interface Get readData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    availableBuffers.increment(1);
	    let resp <- toGet(readBuffer).get();
	    return resp;
	 endmethod
      endinterface
   endinterface
   interface ObjectReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty);
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableBuffers.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(ObjectData#(dataWidth) x);
	    readBuffer.enq(x);
	 endmethod
      endinterface
   endinterface
endmodule

//
// @brief Makes a Dma channel for writing wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaWriteBuffer(DmaWriteBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1, TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth)) writeBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(Bit#(ObjectTagSize))  doneTags <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableWords <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      if (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableWords.read())
	 hasEnoughCapacity.enq(True);
   endrule

   // only issue the writeRequest when sufficient data is available.  This includes the data we have already committed.
   interface ObjectWriteServer dmaServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData;
	 method Action put(ObjectData#(dataWidth) d);
	    writeBuffer.enq(d);
	    availableWords.increment(1);
	 endmethod
      endinterface
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty());
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableWords.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    writeBuffer.deq;
	    return writeBuffer.first;
	 endmethod
      endinterface
      interface Put writeDone = toPut(doneTags);
   endinterface
endmodule

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

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

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

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

import BRAM::*;
import FIFO::*;
import Vector::*;
import Gearbox::*;
import FIFOF::*;
import SpecialFIFOs::*;

import BRAMFIFOFLevel::*;
import GetPut::*;
import Dma::*;

function ObjectReadClient#(dataWidth) orc(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaClient;
function ObjectWriteClient#(dataWidth) owc(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaClient;
function ObjectReadServer#(dataWidth) ors(DmaReadBuffer#(dataWidth,bufferDepth) rb) = rb.dmaServer;
function ObjectWriteServer#(dataWidth) ows(DmaWriteBuffer#(dataWidth,bufferDepth) wb) = wb.dmaServer;

//
// @brief A buffer for reading from a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaReadBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectReadServer #(dataWidth) dmaServer;
   interface ObjectReadClient#(dataWidth) dmaClient;
endinterface

//
// @brief A buffer for writing to a bus of width dataWidth.
//
// @param dataWidth The number of bits in the bus.
// @param bufferDepth The depth of the internal buffer
//
interface DmaWriteBuffer#(numeric type dataWidth, numeric type bufferDepth);
   interface ObjectWriteServer#(dataWidth) dmaServer;
   interface ObjectWriteClient#(dataWidth) dmaClient;
endinterface

//
// @brief Makes a Dma buffer for reading wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaReadBuffer(DmaReadBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1,TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth))  readBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableBuffers <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      Bool ready = (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableBuffers.read());
      if (ready) begin
	 hasEnoughCapacity.enq(True);
      end
   endrule

   // only issue the readRequest when sufficient buffering is available.  This includes the buffering we have already committed.
   interface ObjectReadServer dmaServer;
      interface Put readReq = toPut(reqOutstanding);
      interface Get readData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    availableBuffers.increment(1);
	    let resp <- toGet(readBuffer).get();
	    return resp;
	 endmethod
      endinterface
   endinterface
   interface ObjectReadClient dmaClient;
      interface Get readReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty);
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableBuffers.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Put readData;
	 method Action put(ObjectData#(dataWidth) x);
	    readBuffer.enq(x);
	 endmethod
      endinterface
   endinterface
endmodule

//
// @brief Makes a Dma channel for writing wordSize words from memory.
//
// @param dataWidth The width of the bus in bits.
// @param bufferDepth The depth of the internal buffer
//
module mkDmaWriteBuffer(DmaWriteBuffer#(dataWidth, bufferDepth))
   provisos(Add#(b__, TAdd#(1, TLog#(bufferDepth)), 8),
	    Div#(dataWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,dataWidth),
	    Log#(dataWidthBytes,beatShift));

   FIFO#(ObjectData#(dataWidth)) writeBuffer <- mkSizedFIFO(valueOf(bufferDepth));
   FIFOF#(ObjectRequest)        reqOutstanding <- mkFIFOF();
   FIFOF#(Bit#(6))                        doneTags <- mkFIFOF();
   Ratchet#(TAdd#(1,TLog#(bufferDepth))) availableWords <- mkRatchet(fromInteger(valueOf(bufferDepth)));
   let beat_shift = fromInteger(valueOf(beatShift));

   FIFOF#(Bool) hasEnoughCapacity <- mkFIFOF();
   rule updateReady;
      Bit#(TAdd#(1,TLog#(bufferDepth))) requested = truncate(reqOutstanding.first.burstLen>>beat_shift);
      if (unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)) <= availableWords.read())
	 hasEnoughCapacity.enq(True);
   endrule

   // only issue the writeRequest when sufficient data is available.  This includes the data we have already committed.
   interface ObjectWriteServer dmaServer;
      interface Put writeReq = toPut(reqOutstanding);
      interface Put writeData;
	 method Action put(ObjectData#(dataWidth) d);
	    writeBuffer.enq(d);
	    availableWords.increment(1);
	 endmethod
      endinterface
      interface Get writeDone = toGet(doneTags);
   endinterface
   interface ObjectWriteClient dmaClient;
      interface Get writeReq;
	 method ActionValue#(ObjectRequest) get if (hasEnoughCapacity.notEmpty());
	    hasEnoughCapacity.deq();
	    reqOutstanding.deq;
	    availableWords.decrement(unpack(truncate(reqOutstanding.first.burstLen>>beat_shift)));
	    return reqOutstanding.first;
	 endmethod
      endinterface
      interface Get writeData;
	 method ActionValue#(ObjectData#(dataWidth)) get();
	    writeBuffer.deq;
	    return writeBuffer.first;
	 endmethod
      endinterface
      interface Put writeDone = toPut(doneTags);
   endinterface
endmodule


added byte_enables to Platform, if in use

// Copyright (c) 2015 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 ConnectalConfig::*;
import Vector::*;
import BuildVector::*;
import Portal::*;
import HostInterface::*;
import ConnectalMMU::*;
import MemServer::*;
import ConnectalMemTypes::*;
import CtrlMux::*;
import FIFO::*;
import GetPut::*;
import SpecialFIFOs::*;
import Pipe::*;
import ConnectalMemory::*;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import IfcNames::*;
`include "ConnectalProjectConfig.bsv"
import `PinTypeInclude::*;

interface Platform;
   interface PhysMemSlave#(32,32) slave;
   interface Vector#(NumberOfMasters,PhysMemMaster#(PhysAddrWidth, DataBusWidth)) masters;
   interface Vector#(MaxNumberOfPortals,ReadOnly#(Bool)) interrupt;
   interface `PinType pins;
endinterface

typedef TMax#(TLog#(TSub#(NumberOfTiles,1)),1) TileTagBits;
function Bit#(TSub#(MemTagSize,TileTagBits)) tagLsb(Bit#(MemTagSize) tag); return truncate(tag); endfunction
function Bit#(TileTagBits) tagMsb(Bit#(MemTagSize) tag); return truncate(tag >> valueOf(TSub#(MemTagSize,TileTagBits))); endfunction

module renameReads#(Integer tile, MemReadClient#(DataBusWidth) reader, MemServerIndication err)(MemReadClient#(DataBusWidth));
   interface Get readReq;
      method ActionValue#(MemRequest) get;
	 let req <- reader.readReq.get;
	 Bit#(TSub#(MemTagSize,TileTagBits)) lsb = tagLsb(req.tag);
	 Bit#(TileTagBits) msb = tagMsb(req.tag);
	 if(req.tag != extend(lsb) && valueOf(NumberOfTiles) > 2) begin // one mgmt tile and one user tile
	    $display("renameReads tile tag out of range: 'h%h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Put readData;
      method Action put(MemData#(DataBusWidth) v);
	 reader.readData.put(MemData{data:v.data,
                                     tag:{0,tagLsb(v.tag)},
`ifdef BYTE_ENABLES_MEM_DATA
				     byte_enables: v.byte_enables,
`endif
                                     last:v.last});
      endmethod
   endinterface
endmodule

module renameWrites#(Integer tile, MemWriteClient#(DataBusWidth) writer, MemServerIndication err)(MemWriteClient#(DataBusWidth));
   interface Get writeReq;
      method ActionValue#(MemRequest) get;
	 let req <- writer.writeReq.get;
	 Bit#(TSub#(MemTagSize,TileTagBits)) lsb = tagLsb(req.tag);
	 Bit#(TileTagBits) msb = tagMsb(req.tag);
	 if(req.tag != extend(lsb) && valueOf(NumberOfTiles) > 2) begin // one mgmt tile and one user tile
	    $display("renameWrites tile tag out of range: 'h%h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Get writeData;
      method ActionValue#(MemData#(DataBusWidth)) get;
	 let rv <- writer.writeData.get;
   	 return MemData{data:rv.data,
                        tag:{0,tagLsb(rv.tag)},
`ifdef BYTE_ENABLES_MEM_DATA
                             byte_enables: rv.byte_enables,
`endif
                             last:rv.last};
      endmethod
   endinterface
   interface Put writeDone;
      method Action put(Bit#(MemTagSize) v);
	 writer.writeDone.put({0,tagLsb(v)});
      endmethod
   endinterface
endmodule

module mkPlatform#(Vector#(NumberOfUserTiles, ConnectalTop#(`PinType)) tiles)(Platform);
   /////////////////////////////////////////////////////////////
   // connecting up the tiles

   Vector#(NumberOfUserTiles, PhysMemSlave#(18,32)) tile_slaves;
   Vector#(NumberOfUserTiles, ReadOnly#(Bool)) tile_interrupts;
   Vector#(NumberOfUserTiles, Vector#(NumReadClients, MemReadClient#(DataBusWidth))) tile_read_clients;
   Vector#(NumberOfUserTiles, Vector#(NumWriteClients, MemWriteClient#(DataBusWidth))) tile_write_clients;
   Vector#(NumberOfUserTiles, Vector#(NumReadClients, Integer)) read_client_tile_numbers;
   Vector#(NumberOfUserTiles, Vector#(NumWriteClients, Integer)) write_client_tile_numbers;
   for(Integer i = 0; i < valueOf(NumberOfUserTiles); i=i+1) begin
      tile_slaves[i] = tiles[i].slave;
      let imux <- mkInterruptMux(tiles[i].interrupt);
      //ReadOnly#(Bool) imux = tiles[i].interrupt;
      tile_interrupts[i] = imux;
      tile_read_clients[i] = tiles[i].readers;
      tile_write_clients[i] = tiles[i].writers;
      read_client_tile_numbers[i] = replicate(i);
      write_client_tile_numbers[i] = replicate(i);
   end

   /////////////////////////////////////////////////////////////
   // framework internal portals

   MMUIndicationProxy lMMUIndicationProxy <- mkMMUIndicationProxy(PlatformIfcNames_MMUIndicationH2S);
   MemServerIndicationProxy lMemServerIndicationProxy <- mkMemServerIndicationProxy(PlatformIfcNames_MemServerIndicationH2S);

`ifdef USE_SIMPLE_MMU
   MMU#(PhysAddrWidth) lMMU <- mkSimpleMMU(0,True, lMMUIndicationProxy.ifc);
`else
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationProxy.ifc);
`endif
   Vector#(TMul#(NumberOfUserTiles,NumReadClients), MemReadClient#(DataBusWidth)) tile_read_clients_renamed <- zipWith3M(renameReads, concat(read_client_tile_numbers), concat(tile_read_clients), replicate(lMemServerIndicationProxy.ifc));
   Vector#(TMul#(NumberOfUserTiles,NumWriteClients), MemWriteClient#(DataBusWidth)) tile_write_clients_renamed <- zipWith3M(renameWrites, concat(write_client_tile_numbers), concat(tile_write_clients), replicate(lMemServerIndicationProxy.ifc));
   MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(tile_read_clients_renamed, tile_write_clients_renamed, vec(lMMU), lMemServerIndicationProxy.ifc);

   MMURequestWrapper lMMURequestWrapper <- mkMMURequestWrapper(PlatformIfcNames_MMURequestS2H, lMMU.request);
   MemServerRequestWrapper lMemServerRequestWrapper <- mkMemServerRequestWrapper(PlatformIfcNames_MemServerRequestS2H, lMemServer.request);

   Vector#(4,StdPortal) framework_portals;
   framework_portals[0] = lMMUIndicationProxy.portalIfc;
   framework_portals[1] = lMemServerIndicationProxy.portalIfc;
   framework_portals[2] = lMMURequestWrapper.portalIfc;
   framework_portals[3] = lMemServerRequestWrapper.portalIfc;
   PhysMemSlave#(18,32) framework_ctrl_mux <- mkSlaveMux(framework_portals);
   let framework_intr <- mkInterruptMux(getInterruptVector(framework_portals));

   /////////////////////////////////////////////////////////////
   // expose interface to top

   PhysMemSlave#(32,32) ctrl_mux <- mkPhysMemSlaveMux(cons(framework_ctrl_mux,tile_slaves));
   Vector#(MaxNumberOfPortals, ReadOnly#(Bool)) interrupts = replicate(interface ReadOnly; method Bool _read(); return False; endmethod endinterface);
   interrupts[0] = framework_intr;
   for (Integer i = 1; i < valueOf(NumberOfTiles); i = i + 1)
      interrupts[i] = tile_interrupts[i-1];
   interface interrupt = interrupts;
   interface slave = ctrl_mux;
   interface masters = lMemServer.masters;
   interface pins = tiles[0].pins;
endmodule

// Copyright (c) 2015 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 ConnectalConfig::*;
import Vector::*;
import BuildVector::*;
import Portal::*;
import HostInterface::*;
import ConnectalMMU::*;
import MemServer::*;
import ConnectalMemTypes::*;
import CtrlMux::*;
import FIFO::*;
import GetPut::*;
import SpecialFIFOs::*;
import Pipe::*;
import ConnectalMemory::*;
import MMURequest::*;
import MMUIndication::*;
import MemServerIndication::*;
import MemServerRequest::*;
import IfcNames::*;
`include "ConnectalProjectConfig.bsv"
import `PinTypeInclude::*;

interface Platform;
   interface PhysMemSlave#(32,32) slave;
   interface Vector#(NumberOfMasters,PhysMemMaster#(PhysAddrWidth, DataBusWidth)) masters;
   interface Vector#(MaxNumberOfPortals,ReadOnly#(Bool)) interrupt;
   interface `PinType pins;
endinterface

typedef TMax#(TLog#(TSub#(NumberOfTiles,1)),1) TileTagBits;
function Bit#(TSub#(MemTagSize,TileTagBits)) tagLsb(Bit#(MemTagSize) tag); return truncate(tag); endfunction
function Bit#(TileTagBits) tagMsb(Bit#(MemTagSize) tag); return truncate(tag >> valueOf(TSub#(MemTagSize,TileTagBits))); endfunction

module renameReads#(Integer tile, MemReadClient#(DataBusWidth) reader, MemServerIndication err)(MemReadClient#(DataBusWidth));
   interface Get readReq;
      method ActionValue#(MemRequest) get;
	 let req <- reader.readReq.get;
	 Bit#(TSub#(MemTagSize,TileTagBits)) lsb = tagLsb(req.tag);
	 Bit#(TileTagBits) msb = tagMsb(req.tag);
	 if(req.tag != extend(lsb) && valueOf(NumberOfTiles) > 2) begin // one mgmt tile and one user tile
	    $display("renameReads tile tag out of range: 'h%h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Put readData;
      method Action put(MemData#(DataBusWidth) v);
	 reader.readData.put(MemData{data:v.data, tag:{0,tagLsb(v.tag)}, last:v.last});
      endmethod
   endinterface
endmodule

module renameWrites#(Integer tile, MemWriteClient#(DataBusWidth) writer, MemServerIndication err)(MemWriteClient#(DataBusWidth));
   interface Get writeReq;
      method ActionValue#(MemRequest) get;
	 let req <- writer.writeReq.get;
	 Bit#(TSub#(MemTagSize,TileTagBits)) lsb = tagLsb(req.tag);
	 Bit#(TileTagBits) msb = tagMsb(req.tag);
	 if(req.tag != extend(lsb) && valueOf(NumberOfTiles) > 2) begin // one mgmt tile and one user tile
	    $display("renameWrites tile tag out of range: 'h%h", req.tag);
	    err.error(extend(pack(DmaErrorTileTagOutOfRange)), req.sglId, extend(req.tag), fromInteger(tile));
	 end
	 req.tag = {fromInteger(tile),lsb};
	 return req;
      endmethod
   endinterface
   interface Get writeData;
      method ActionValue#(MemData#(DataBusWidth)) get;
	 let rv <- writer.writeData.get;
   	 return MemData{data:rv.data, tag:{0,tagLsb(rv.tag)}, last:rv.last};
      endmethod
   endinterface
   interface Put writeDone;
      method Action put(Bit#(MemTagSize) v);
	 writer.writeDone.put({0,tagLsb(v)});
      endmethod
   endinterface
endmodule

module mkPlatform#(Vector#(NumberOfUserTiles, ConnectalTop#(`PinType)) tiles)(Platform);
   /////////////////////////////////////////////////////////////
   // connecting up the tiles

   Vector#(NumberOfUserTiles, PhysMemSlave#(18,32)) tile_slaves;
   Vector#(NumberOfUserTiles, ReadOnly#(Bool)) tile_interrupts;
   Vector#(NumberOfUserTiles, Vector#(NumReadClients, MemReadClient#(DataBusWidth))) tile_read_clients;
   Vector#(NumberOfUserTiles, Vector#(NumWriteClients, MemWriteClient#(DataBusWidth))) tile_write_clients;
   Vector#(NumberOfUserTiles, Vector#(NumReadClients, Integer)) read_client_tile_numbers;
   Vector#(NumberOfUserTiles, Vector#(NumWriteClients, Integer)) write_client_tile_numbers;
   for(Integer i = 0; i < valueOf(NumberOfUserTiles); i=i+1) begin
      tile_slaves[i] = tiles[i].slave;
      let imux <- mkInterruptMux(tiles[i].interrupt);
      //ReadOnly#(Bool) imux = tiles[i].interrupt;
      tile_interrupts[i] = imux;
      tile_read_clients[i] = tiles[i].readers;
      tile_write_clients[i] = tiles[i].writers;
      read_client_tile_numbers[i] = replicate(i);
      write_client_tile_numbers[i] = replicate(i);
   end

   /////////////////////////////////////////////////////////////
   // framework internal portals

   MMUIndicationProxy lMMUIndicationProxy <- mkMMUIndicationProxy(PlatformIfcNames_MMUIndicationH2S);
   MemServerIndicationProxy lMemServerIndicationProxy <- mkMemServerIndicationProxy(PlatformIfcNames_MemServerIndicationH2S);

`ifdef USE_SIMPLE_MMU
   MMU#(PhysAddrWidth) lMMU <- mkSimpleMMU(0,True, lMMUIndicationProxy.ifc);
`else
   MMU#(PhysAddrWidth) lMMU <- mkMMU(0,True, lMMUIndicationProxy.ifc);
`endif
   Vector#(TMul#(NumberOfUserTiles,NumReadClients), MemReadClient#(DataBusWidth)) tile_read_clients_renamed <- zipWith3M(renameReads, concat(read_client_tile_numbers), concat(tile_read_clients), replicate(lMemServerIndicationProxy.ifc));
   Vector#(TMul#(NumberOfUserTiles,NumWriteClients), MemWriteClient#(DataBusWidth)) tile_write_clients_renamed <- zipWith3M(renameWrites, concat(write_client_tile_numbers), concat(tile_write_clients), replicate(lMemServerIndicationProxy.ifc));
   MemServer#(PhysAddrWidth,DataBusWidth,NumberOfMasters) lMemServer <- mkMemServer(tile_read_clients_renamed, tile_write_clients_renamed, vec(lMMU), lMemServerIndicationProxy.ifc);

   MMURequestWrapper lMMURequestWrapper <- mkMMURequestWrapper(PlatformIfcNames_MMURequestS2H, lMMU.request);
   MemServerRequestWrapper lMemServerRequestWrapper <- mkMemServerRequestWrapper(PlatformIfcNames_MemServerRequestS2H, lMemServer.request);

   Vector#(4,StdPortal) framework_portals;
   framework_portals[0] = lMMUIndicationProxy.portalIfc;
   framework_portals[1] = lMemServerIndicationProxy.portalIfc;
   framework_portals[2] = lMMURequestWrapper.portalIfc;
   framework_portals[3] = lMemServerRequestWrapper.portalIfc;
   PhysMemSlave#(18,32) framework_ctrl_mux <- mkSlaveMux(framework_portals);
   let framework_intr <- mkInterruptMux(getInterruptVector(framework_portals));

   /////////////////////////////////////////////////////////////
   // expose interface to top

   PhysMemSlave#(32,32) ctrl_mux <- mkPhysMemSlaveMux(cons(framework_ctrl_mux,tile_slaves));
   Vector#(MaxNumberOfPortals, ReadOnly#(Bool)) interrupts = replicate(interface ReadOnly; method Bool _read(); return False; endmethod endinterface);
   interrupts[0] = framework_intr;
   for (Integer i = 1; i < valueOf(NumberOfTiles); i = i + 1)
      interrupts[i] = tile_interrupts[i-1];
   interface interrupt = interrupts;
   interface slave = ctrl_mux;
   interface masters = lMemServer.masters;
   interface pins = tiles[0].pins;
endmodule


Replaced mkNonPipelinedDivider with mkDivider for single-precision FP division

// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved
package FPU;

import FIFOF :: *;
import RegFile :: *;
import GetPut :: *;
import ClientServer :: *;

import FloatingPoint :: *;
import Divide :: *;
import SquareRoot ::*;
import ISA_Decls :: *;

// ================================================================
// Type definitions
typedef FloatingPoint#(11,52) FDouble;
typedef FloatingPoint#(8,23)  FSingle;

typedef union tagged {
   FDouble D;
   FSingle S;
   } FloatU deriving(Bits,Eq);

typedef Tuple5#( FloatU,FloatU,FloatU,RoundMode,FpuOp) Fpu_Req;
typedef Tuple2#( FloatU, FloatingPoint::Exception )       Fpu_Rsp;

`ifdef ISA_D
typedef Tuple2#( FDouble, FloatingPoint::Exception )      FpuR;
`else
typedef Tuple2#( FSingle, FloatingPoint::Exception )      FpuR;
`endif

interface FPU_IFC;
   interface Server #( Fpu_Req, Fpu_Rsp ) server_core;

   // ---- Reset
   interface Server #(Token, Token) server_reset;
endinterface

(* synthesize *)
module mkFPU ( FPU_IFC );
`ifdef INCLUDE_FDIV
`ifdef ISA_D
   Server# (Tuple2# (UInt# (114), UInt# (57))
          , Tuple2# (UInt# (57) , UInt# (57))) _div <- mkNonPipelinedDivider(2);
   Server# (Tuple3#(FDouble, FDouble, RoundMode)
          , FpuR) fpu_div  <- mkFloatingPointDivider(_div);
`else
   Server# (Tuple2# (UInt #(56), UInt #(28))
          , Tuple2# (UInt #(28), UInt #(28))) _div <- mkDivider(1);
   Server# (Tuple3# (FSingle, FSingle, RoundMode)
          , FpuR) fpu_div <- mkFloatingPointDivider(_div);
`endif
`endif

`ifdef INCLUDE_FSQRT
`ifdef ISA_D
   Server# (UInt# (116)
          , Tuple2# (UInt# (116), Bool)) _sqrt <- mkNonPipelinedSquareRooter(2);
   Server# (Tuple2# (FDouble, RoundMode)
          , FpuR) fpu_sqr <- mkFloatingPointSquareRooter(_sqrt);
`else
   Server# (UInt# (60)
          , Tuple2# (UInt# (60), Bool)) _sqrt <- mkNonPipelinedSquareRooter(2);
   Server# (Tuple2# (FSingle, RoundMode)
          , FpuR) fpu_sqr <- mkFloatingPointSquareRooter(_sqrt);
`endif
`endif

`ifdef ISA_D
   Server# (Tuple4# (Maybe# (FDouble), FDouble, FDouble, RoundMode)
          , FpuR ) fpu_madd <- mkFloatingPointFusedMultiplyAccumulate;
`else
   Server# (Tuple4# (Maybe# (FSingle), FSingle, FSingle, RoundMode)
          , FpuR ) fpu_madd <- mkFloatingPointFusedMultiplyAccumulate;
`endif

   FIFOF #(Token)          resetReqsF           <- mkFIFOF;
   FIFOF #(Token)          resetRspsF           <- mkFIFOF;

   FIFOF#( Fpu_Req )  iFifo        <- mkFIFOF; // TODO: bypass fifos?
   FIFOF#( Fpu_Rsp )  oFifo        <- mkFIFOF; // TODO: bypass fifos?
   FIFOF#( RoundMode ) rmdFifo     <- mkFIFOF; // TODO: bypass fifos?
`ifdef ISA_D
   FIFOF#( Bool )     isDoubleFifo <- mkFIFOF; // TODO: bypass fifos?
`endif
   FIFOF#( Bool )     isNegateFifo <- mkFIFOF; // TODO: bypass fifos?
   Reg#(FpuR)         resWire      <- mkWire;

   function FDouble toDouble( FloatU x, RoundMode rmode );
      if (x matches tagged S .val) begin
         let r = convert( val , rmode , True );
         return tpl_1(r);
      end
      else if (x matches tagged D .val)
         return val;
      else
         return unpack(0);
   endfunction

   let x    = iFifo.first();
   let op1  = tpl_1(x);
   let op2  = tpl_2(x);
   let op3  = tpl_3(x);
   let rmd  = tpl_4(x);
   let iop  = tpl_5(x);

`ifdef ISA_D
   FDouble opd1 = toDouble(op1, rmd);
   FDouble opd2 = toDouble(op2, rmd);
   FDouble opd3 = toDouble(op3, rmd);
`else
   FSingle opd1 = op1.S;
   FSingle opd2 = op2.S;
   FSingle opd3 = op3.S;
`endif

   rule start_op;
      iFifo.deq();
`ifdef ISA_D
      if (op1 matches tagged D .val) isDoubleFifo.enq(True);
      else                           isDoubleFifo.enq(False);
`endif

      if      (iop == FPNMAdd)    isNegateFifo.enq(True);
      else if (iop == FPNMSub)    isNegateFifo.enq(True);
      else                        isNegateFifo.enq(False);

      rmdFifo.enq(rmd);

      case ( iop )
         FPAdd:   fpu_madd.request.put (tuple4(Valid(opd1), opd2,         one(False), rmd) );
         FPSub:   fpu_madd.request.put (tuple4(Valid(opd1), negate(opd2), one(False), rmd) );
         FPMul:   fpu_madd.request.put (tuple4(Invalid,     opd1,         opd2,       rmd) );
`ifdef INCLUDE_FDIV
         FPDiv:   fpu_div.request.put (tuple3 (opd1, opd2, rmd) );
`endif
`ifdef INCLUDE_FSQRT
         FPSqrt:  fpu_sqr.request.put (tuple2(opd1, rmd) );
`endif
         FPMAdd:  fpu_madd.request.put(  tuple4(Valid(opd3),         opd1, opd2, rmd) );
         FPMSub:  fpu_madd.request.put(  tuple4(Valid(negate(opd3)), opd1, opd2, rmd) );
         FPNMAdd: fpu_madd.request.put(  tuple4(Valid(opd3),         opd1, opd2, rmd) );
         FPNMSub: fpu_madd.request.put(  tuple4(Valid(negate(opd3)), opd1, opd2, rmd) );
      endcase

   endrule

   // rule generator for handling responses from multi-cycle pipes
   function Rules fn_genMultCycResRules (Server #(req, FpuR) pipe);
      return (rules
         rule getResFromPipe;
            let res <- pipe.response.get ();
            resWire <= res;
         endrule
      endrules);
   endfunction

   let rl_resRules = emptyRules;
   rl_resRules = rJoin (rl_resRules, fn_genMultCycResRules (fpu_madd));
`ifdef INCLUDE_FDIV
   rl_resRules = rJoinMutuallyExclusive (rl_resRules, fn_genMultCycResRules (fpu_div));
`endif
`ifdef INCLUDE_FSQRT
   rl_resRules = rJoinMutuallyExclusive (rl_resRules, fn_genMultCycResRules (fpu_sqr));
`endif
   addRules (rl_resRules);

   rule passResult;
`ifdef ISA_D
      isDoubleFifo.deq();
      let is64Bits = isDoubleFifo.first();
`endif

      isNegateFifo.deq();
      let negateResult = isNegateFifo.first();

      rmdFifo.deq();
      let rmode = rmdFifo.first();

`ifdef ISA_D
      if (is64Bits) begin
         FDouble   v  = tpl_1(resWire);
         FloatingPoint::Exception ex = tpl_2(resWire);
         if (negateResult)
            v = negate( v );
         FloatU res = tagged D v;
         oFifo.enq( tuple2( res, ex ) );
      end
      else begin
         Tuple2#(FSingle,FloatingPoint::Exception) sres = convert( tpl_1(resWire) , rmode , True );
         FSingle   v  = tpl_1(sres);
         FloatingPoint::Exception ex = tpl_2(resWire) | tpl_2(sres);
         if (negateResult)
            v = negate( v );
         FloatU res = tagged S v;
         oFifo.enq( tuple2( res, ex ) );
      end
`else
      FSingle   v  = tpl_1(resWire);
      FloatingPoint::Exception ex = tpl_2(resWire);
      if (negateResult)
         v = negate( v );
      FloatU res = tagged S v;
      oFifo.enq( tuple2( res, ex ) );
`endif
   endrule

   rule rl_reset;
      resetReqsF.deq;
      iFifo.clear;
      oFifo.clear;
      rmdFifo.clear;
`ifdef ISA_D
      isDoubleFifo.clear;
`endif
      isNegateFifo.clear;
      resetRspsF.enq (?);
   endrule

   // =============================================================
   // INTERFACE
   // ---- Reset
   interface server_reset = toGPServer (resetReqsF, resetRspsF);
   interface server_core = toGPServer ( iFifo, oFifo );
endmodule
endpackage

// Copyright (c) 2013-2019 Bluespec, Inc. All Rights Reserved
package FPU;

import FIFOF :: *;
import RegFile :: *;
import GetPut :: *;
import ClientServer :: *;

import FloatingPoint :: *;
import Divide :: *;
import SquareRoot ::*;
import ISA_Decls :: *;

// ================================================================
// Type definitions
typedef FloatingPoint#(11,52) FDouble;
typedef FloatingPoint#(8,23)  FSingle;

typedef union tagged {
   FDouble D;
   FSingle S;
   } FloatU deriving(Bits,Eq);

typedef Tuple5#( FloatU,FloatU,FloatU,RoundMode,FpuOp) Fpu_Req;
typedef Tuple2#( FloatU, FloatingPoint::Exception )       Fpu_Rsp;

`ifdef ISA_D
typedef Tuple2#( FDouble, FloatingPoint::Exception )      FpuR;
`else
typedef Tuple2#( FSingle, FloatingPoint::Exception )      FpuR;
`endif

interface FPU_IFC;
   interface Server #( Fpu_Req, Fpu_Rsp ) server_core;

   // ---- Reset
   interface Server #(Token, Token) server_reset;
endinterface

(* synthesize *)
module mkFPU ( FPU_IFC );
`ifdef INCLUDE_FDIV
`ifdef ISA_D
   Server# (Tuple2# (UInt# (114), UInt# (57))
          , Tuple2# (UInt# (57) , UInt# (57))) _div <- mkNonPipelinedDivider(2);
   Server# (Tuple3#(FDouble, FDouble, RoundMode)
          , FpuR) fpu_div  <- mkFloatingPointDivider(_div);
`else
   Server# (Tuple2# (UInt #(56), UInt #(28))
          , Tuple2# (UInt #(28), UInt #(28))) _div <- mkNonPipelinedDivider(2);
   Server# (Tuple3# (FSingle, FSingle, RoundMode)
          , FpuR) fpu_div <- mkFloatingPointDivider(_div);
`endif
`endif

`ifdef INCLUDE_FSQRT
`ifdef ISA_D
   Server# (UInt# (116)
          , Tuple2# (UInt# (116), Bool)) _sqrt <- mkNonPipelinedSquareRooter(2);
   Server# (Tuple2# (FDouble, RoundMode)
          , FpuR) fpu_sqr <- mkFloatingPointSquareRooter(_sqrt);
`else
   Server# (UInt# (60)
          , Tuple2# (UInt# (60), Bool)) _sqrt <- mkNonPipelinedSquareRooter(2);
   Server# (Tuple2# (FSingle, RoundMode)
          , FpuR) fpu_sqr <- mkFloatingPointSquareRooter(_sqrt);
`endif
`endif

`ifdef ISA_D
   Server# (Tuple4# (Maybe# (FDouble), FDouble, FDouble, RoundMode)
          , FpuR ) fpu_madd <- mkFloatingPointFusedMultiplyAccumulate;
`else
   Server# (Tuple4# (Maybe# (FSingle), FSingle, FSingle, RoundMode)
          , FpuR ) fpu_madd <- mkFloatingPointFusedMultiplyAccumulate;
`endif

   FIFOF #(Token)          resetReqsF           <- mkFIFOF;
   FIFOF #(Token)          resetRspsF           <- mkFIFOF;

   FIFOF#( Fpu_Req )  iFifo        <- mkFIFOF; // TODO: bypass fifos?
   FIFOF#( Fpu_Rsp )  oFifo        <- mkFIFOF; // TODO: bypass fifos?
   FIFOF#( RoundMode ) rmdFifo     <- mkFIFOF; // TODO: bypass fifos?
`ifdef ISA_D
   FIFOF#( Bool )     isDoubleFifo <- mkFIFOF; // TODO: bypass fifos?
`endif
   FIFOF#( Bool )     isNegateFifo <- mkFIFOF; // TODO: bypass fifos?
   Reg#(FpuR)         resWire      <- mkWire;

   function FDouble toDouble( FloatU x, RoundMode rmode );
      if (x matches tagged S .val) begin
         let r = convert( val , rmode , True );
         return tpl_1(r);
      end
      else if (x matches tagged D .val)
         return val;
      else
         return unpack(0);
   endfunction

   let x    = iFifo.first();
   let op1  = tpl_1(x);
   let op2  = tpl_2(x);
   let op3  = tpl_3(x);
   let rmd  = tpl_4(x);
   let iop  = tpl_5(x);

`ifdef ISA_D
   FDouble opd1 = toDouble(op1, rmd);
   FDouble opd2 = toDouble(op2, rmd);
   FDouble opd3 = toDouble(op3, rmd);
`else
   FSingle opd1 = op1.S;
   FSingle opd2 = op2.S;
   FSingle opd3 = op3.S;
`endif

   rule start_op;
      iFifo.deq();
`ifdef ISA_D
      if (op1 matches tagged D .val) isDoubleFifo.enq(True);
      else                           isDoubleFifo.enq(False);
`endif

      if      (iop == FPNMAdd)    isNegateFifo.enq(True);
      else if (iop == FPNMSub)    isNegateFifo.enq(True);
      else                        isNegateFifo.enq(False);

      rmdFifo.enq(rmd);

      case ( iop )
         FPAdd:   fpu_madd.request.put (tuple4(Valid(opd1), opd2,         one(False), rmd) );
         FPSub:   fpu_madd.request.put (tuple4(Valid(opd1), negate(opd2), one(False), rmd) );
         FPMul:   fpu_madd.request.put (tuple4(Invalid,     opd1,         opd2,       rmd) );
`ifdef INCLUDE_FDIV
         FPDiv:   fpu_div.request.put (tuple3 (opd1, opd2, rmd) );
`endif
`ifdef INCLUDE_FSQRT
         FPSqrt:  fpu_sqr.request.put (tuple2(opd1, rmd) );
`endif
         FPMAdd:  fpu_madd.request.put(  tuple4(Valid(opd3),         opd1, opd2, rmd) );
         FPMSub:  fpu_madd.request.put(  tuple4(Valid(negate(opd3)), opd1, opd2, rmd) );
         FPNMAdd: fpu_madd.request.put(  tuple4(Valid(opd3),         opd1, opd2, rmd) );
         FPNMSub: fpu_madd.request.put(  tuple4(Valid(negate(opd3)), opd1, opd2, rmd) );
      endcase

   endrule

   // rule generator for handling responses from multi-cycle pipes
   function Rules fn_genMultCycResRules (Server #(req, FpuR) pipe);
      return (rules
         rule getResFromPipe;
            let res <- pipe.response.get ();
            resWire <= res;
         endrule
      endrules);
   endfunction

   let rl_resRules = emptyRules;
   rl_resRules = rJoin (rl_resRules, fn_genMultCycResRules (fpu_madd));
`ifdef INCLUDE_FDIV
   rl_resRules = rJoinMutuallyExclusive (rl_resRules, fn_genMultCycResRules (fpu_div));
`endif
`ifdef INCLUDE_FSQRT
   rl_resRules = rJoinMutuallyExclusive (rl_resRules, fn_genMultCycResRules (fpu_sqr));
`endif
   addRules (rl_resRules);

   rule passResult;
`ifdef ISA_D
      isDoubleFifo.deq();
      let is64Bits = isDoubleFifo.first();
`endif

      isNegateFifo.deq();
      let negateResult = isNegateFifo.first();

      rmdFifo.deq();
      let rmode = rmdFifo.first();

`ifdef ISA_D
      if (is64Bits) begin
         FDouble   v  = tpl_1(resWire);
         FloatingPoint::Exception ex = tpl_2(resWire);
         if (negateResult)
            v = negate( v );
         FloatU res = tagged D v;
         oFifo.enq( tuple2( res, ex ) );
      end
      else begin
         Tuple2#(FSingle,FloatingPoint::Exception) sres = convert( tpl_1(resWire) , rmode , True );
         FSingle   v  = tpl_1(sres);
         FloatingPoint::Exception ex = tpl_2(resWire) | tpl_2(sres);
         if (negateResult)
            v = negate( v );
         FloatU res = tagged S v;
         oFifo.enq( tuple2( res, ex ) );
      end
`else
      FSingle   v  = tpl_1(resWire);
      FloatingPoint::Exception ex = tpl_2(resWire);
      if (negateResult)
         v = negate( v );
      FloatU res = tagged S v;
      oFifo.enq( tuple2( res, ex ) );
`endif
   endrule

   rule rl_reset;
      resetReqsF.deq;
      iFifo.clear;
      oFifo.clear;
      rmdFifo.clear;
`ifdef ISA_D
      isDoubleFifo.clear;
`endif
      isNegateFifo.clear;
      resetRspsF.enq (?);
   endrule

   // =============================================================
   // INTERFACE
   // ---- Reset
   interface server_reset = toGPServer (resetReqsF, resetRspsF);
   interface server_core = toGPServer ( iFifo, oFifo );
endmodule
endpackage