drive axi signals size, burst, prot, and cache in mkPhysMemSlave

// 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 Clocks::*;
import FIFOF::*;
import CFFIFO::*;
import GetPut::*;
import MemTypes::*;
import EHRM::*;
import Axi4MasterSlave::*;

interface AxiMasterBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(1)     aresetn();
    method Bit#(tagWidth)     arid();
    method Bit#(4)     arlen();
    method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(2)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(tagWidth)     awid();
    method Bit#(4)     awlen();
    method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(2)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(tagWidth) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rid(Bit#(tagWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(tagWidth)     wid();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
    interface extraType   extra;
endinterface

interface HPType;
    method Bit#(3)     racount();
    method Bit#(8)     rcount();
    method Action      rdissuecap1en(Bit#(1) v);
    method Bit#(6)     wacount();
    method Bit#(8)     wcount();
    method Action      wrissuecap1en(Bit#(1) v);
endinterface

interface ACPType;
    method Action      aruser(Bit#(5) v);
    method Action      awuser(Bit#(5) v);
endinterface

interface AxiSlaveBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Action      araddr(Bit#(addrWidth) v);
    method Action      arburst(Bit#(2) v);
    method Action      arcache(Bit#(4) v);
    method Bit#(1)     aresetn();
    method Action      arid(Bit#(tagWidth) v);
    method Action      arlen(Bit#(4) v);
    method Action      arlock(Bit#(2) v);
    method Action      arprot(Bit#(3) v);
    method Action      arqos(Bit#(4) v);
    method Bit#(1)     arready();
    method Action      arsize(Bit#(2) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Action      awburst(Bit#(2) v);
    method Action      awcache(Bit#(4) v);
    method Action      awid(Bit#(tagWidth) v);
    method Action      awlen(Bit#(4) v);
    method Action      awlock(Bit#(2) v);
    method Action      awprot(Bit#(3) v);
    method Action      awqos(Bit#(4) v);
    method Bit#(1)     awready();
    method Action      awsize(Bit#(2) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(tagWidth)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Action      wid(Bit#(tagWidth) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(TDiv#(dataWidth,8)) v);
    method Action      wvalid(Bit#(1) v);
    method Bit#(tagWidth)     rid();
    interface extraType   extra;
endinterface

interface Axi4MasterBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(1)     aresetn();
    method Bit#(tagWidth)     arid();
    method Bit#(8)     arlen();
    method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(tagWidth)     awid();
    method Bit#(8)     awlen();
    method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(tagWidth) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rid(Bit#(tagWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(tagWidth)     wid();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
    interface extraType   extra;
endinterface

interface Axi4MasterUntaggedBits#(numeric type addrWidth, numeric type dataWidth);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(8)     arlen();
    //method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    //method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(8)     awlen();
    //method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    //method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
endinterface

typeclass ToAxi4MasterBits#(type atype, type btype);
   function atype toAxi4MasterBits(btype b);
endtypeclass

instance ToAxi4MasterBits#(Axi4MasterBits#(addrWidth,dataWidth,tagWidth,Empty), Axi4MasterUntaggedBits#(addrWidth,dataWidth));
function Axi4MasterBits#(addrWidth,dataWidth,tagWidth,Empty) toAxi4MasterBits(Axi4MasterUntaggedBits#(addrWidth,dataWidth) m);
   return (interface Axi4MasterBits#(addrWidth,dataWidth,tagWidth,Empty);
    method araddr = m.araddr;
      method arburst = m.arburst;
      method arcache = m.arcache;
      //method aresetn = no_reset;
      method Bit#(tagWidth)     arid(); return 0; endmethod
      method arlen = m.arlen;
      //method arlock = m.arlock;
      method arprot = m.arprot;
      //method arqos = m.arqos;
      method arready = m.arready;
      method arsize = m.arsize;
      method arvalid = m.arvalid;
      method awaddr = m.awaddr;
      method awburst = m.awburst;
      method awcache = m.awcache;
      method Bit#(tagWidth)     awid(); return 0; endmethod
      method awlen = m.awlen;
      //method awlock = m.awlock;
      method awprot = m.awprot;
      //method awqos = m.awqos;
      method awready = m.awready;
      method awsize = m.awsize;
      method awvalid = m.awvalid;
      method Action      bid(Bit#(tagWidth) v); endmethod
      method bready = m.bready;
      method bresp = m.bresp;
      method bvalid = m.bvalid;
      method rdata = m.rdata;
      method Action      rid(Bit#(tagWidth) v); endmethod
      method rlast = m.rlast;
      method rready = m.rready;
      method rresp = m.rresp;
      method rvalid = m.rvalid;
      method wdata = m.wdata;
      method Bit#(tagWidth)     wid(); return 0; endmethod
      method wlast = m.wlast;
      method wready = m.wready;
      method wstrb = m.wstrb;
      method wvalid = m.wvalid;
      interface extra = ?;
      endinterface);
endfunction
endinstance

interface Axi4SlaveBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Action      araddr(Bit#(addrWidth) v);
    method Action      arburst(Bit#(2) v);
    method Action      arcache(Bit#(4) v);
    method Bit#(1)     aresetn();
    method Action      arid(Bit#(tagWidth) v);
    method Action      arlen(Bit#(8) v);
    method Action      arlock(Bit#(2) v);
    method Action      arprot(Bit#(3) v);
    method Action      arqos(Bit#(4) v);
    method Bit#(1)     arready();
    method Action      arsize(Bit#(3) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Action      awburst(Bit#(2) v);
    method Action      awcache(Bit#(4) v);
    method Action      awid(Bit#(tagWidth) v);
    method Action      awlen(Bit#(8) v);
    method Action      awlock(Bit#(2) v);
    method Action      awprot(Bit#(3) v);
    method Action      awqos(Bit#(4) v);
    method Bit#(1)     awready();
    method Action      awsize(Bit#(3) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(tagWidth)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Action      wid(Bit#(tagWidth) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(TDiv#(dataWidth,8)) v);
    method Action      wvalid(Bit#(1) v);
    method Bit#(tagWidth)     rid();
    interface extraType   extra;
endinterface

interface Axi4SlaveLiteBits#(numeric type addrWidth, numeric type dataWidth);
    method Action      araddr(Bit#(addrWidth) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Bit#(1)     awready();
    method Action      awvalid(Bit#(1) v);
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Bit#(1)     wready();
    method Action      wvalid(Bit#(1) v);
endinterface

typeclass ToAxi4SlaveBits#(type atype, type btype);
   function atype toAxi4SlaveBits(btype b);
endtypeclass

module mkAxiFifoF(FIFOF#(t)) provisos(Bits#(t, tSz));
  Ehr#(2, t) da <- mkEhr(?);
  Ehr#(2, Bool) va <- mkEhr(False);
  Ehr#(2, t) db <- mkEhr(?);
  Ehr#(2, Bool) vb <- mkEhr(False);

  rule canon if(vb[1] && !va[1]);
    da[1] <= db[1];
    va[1] <= True;
    vb[1] <= False;
  endrule

  method Bool notFull = !vb[0];

  method Action enq(t x) if(!vb[0]);
    db[0] <= x;
    vb[0] <= True;
  endmethod

  method Bool notEmpty = va[0];

  method Action deq if (va[0]);
    va[0] <= False;
  endmethod

  // no implicit guard, to simplify rule guards below
  method t first;
    return da[0];
  endmethod

  // conflicts with enq, deq, but we do not call it
  method Action clear;
    vb[0] <= False;
    va[0] <= False;
  endmethod
endmodule

typeclass MkPhysMemSlave#(type srctype, numeric type addrWidth, numeric type dataWidth);
   module mkPhysMemSlave#(srctype axiSlave)(PhysMemSlave#(addrWidth,dataWidth));
endtypeclass

instance MkPhysMemSlave#(Axi4SlaveLiteBits#(axiAddrWidth,dataWidth),addrWidth,dataWidth)
      provisos (Add#(axiAddrWidth,a__,addrWidth));
   module mkPhysMemSlave#(Axi4SlaveLiteBits#(axiAddrWidth,dataWidth) axiSlave)(PhysMemSlave#(addrWidth,dataWidth));
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) rfifo <- mkAxiFifoF();
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) wfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) bfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) rtagfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) wtagfifo <- mkAxiFifoF();

      rule rl_arvalid_araddr;
	 axiSlave.arvalid(pack(arfifo.notEmpty && rtagfifo.notFull));
	 let addr = 0;
	 if (arfifo.notEmpty)
	    addr = truncate(arfifo.first.addr);
	 axiSlave.araddr(addr);
      endrule
      rule rl_arfifo if (axiSlave.arready() == 1);
	 let req <- toGet(arfifo).get();
	 rtagfifo.enq(req.tag);
      endrule
      rule rl_rready;
	 axiSlave.rready(pack(rfifo.notFull && rtagfifo.notEmpty));
      endrule
      rule rl_rdata if (axiSlave.rvalid() == 1);
	 let rtag <- toGet(rtagfifo).get();
	 rfifo.enq(MemData { data: axiSlave.rdata(), tag: rtag } );
      endrule

      rule rl_awvalid_awaddr;
	 axiSlave.awvalid(pack(awfifo.notEmpty && wtagfifo.notFull));
	 let addr = 0;
	 if (awfifo.notEmpty)
	    addr = truncate(awfifo.first.addr);
	 axiSlave.awaddr(addr);
      endrule
      rule rl_awfifo if (axiSlave.awready() == 1);
	 let req <- toGet(awfifo).get();
	 wtagfifo.enq(req.tag);
      endrule
      rule rl_wvalid;
	 axiSlave.wvalid(pack(wfifo.notEmpty));
	 let wdata = 0;
	 if (wfifo.notEmpty)
	    wdata = wfifo.first.data;
	 axiSlave.wdata(wdata);
      endrule
      rule rl_wdata if (axiSlave.wready() == 1);
	 let md <- toGet(wfifo).get();
      endrule
      rule rl_bready;
	 axiSlave.bready(pack(wtagfifo.notEmpty && bfifo.notFull));
      endrule
      rule rl_done if (axiSlave.bvalid() == 1);
	 let tag <- toGet(wtagfifo).get();
	 bfifo.enq(tag);
      endrule

      interface PhysMemReadServer read_server;
	 interface Put readReq = toPut(arfifo);
	 interface Get readData = toGet(rfifo);
      endinterface
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = toPut(awfifo);
	 interface Put writeData = toPut(wfifo);
	 interface Get writeDone = toGet(bfifo);
      endinterface
   endmodule
endinstance

//FIXME burst transfers
instance MkPhysMemSlave#(Axi4SlaveBits#(axiAddrWidth,dataWidth,tagWidth,Empty),addrWidth,dataWidth)
      provisos (Add#(axiAddrWidth,a__,addrWidth),
		Add#(b__, tagWidth, 6));
   module mkPhysMemSlave#(Axi4SlaveBits#(axiAddrWidth,dataWidth,tagWidth,Empty) axiSlave)(PhysMemSlave#(addrWidth,dataWidth));
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) rfifo <- mkAxiFifoF();
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) wfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) bfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) rtagfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) wtagfifo <- mkAxiFifoF();

      rule rl_arvalid_araddr;
	 axiSlave.arvalid(pack(arfifo.notEmpty && rtagfifo.notFull));
	 Bit#(axiAddrWidth) addr = 0;
	 Bit#(tagWidth) id = 0;
	 if (arfifo.notEmpty) begin
	    addr = truncate(arfifo.first.addr);
	    id = truncate(arfifo.first.tag);
	 end
	 axiSlave.araddr(addr);
	 axiSlave.arid(id);
	 axiSlave.arsize(axiBusSize(valueOf(dataWidth)));
	 axiSlave.arburst(2'b01);
	 axiSlave.arprot(3'b000);
	 axiSlave.arcache(4'b0011);
      endrule
      rule rl_arfifo if (axiSlave.arready() == 1);
	 let req <- toGet(arfifo).get();
	 rtagfifo.enq(req.tag);
      endrule
      rule rl_rready;
	 axiSlave.rready(pack(rfifo.notFull && rtagfifo.notEmpty));
      endrule
      rule rl_rdata if (axiSlave.rvalid() == 1);
	 let rtag <- toGet(rtagfifo).get();
	 rfifo.enq(MemData { data: axiSlave.rdata(), tag: rtag } );
      endrule

      rule rl_awvalid_awaddr;
	 axiSlave.awvalid(pack(awfifo.notEmpty && wtagfifo.notFull));
	 Bit#(axiAddrWidth) addr = 0;
	 Bit#(tagWidth) id = 0;
	 if (awfifo.notEmpty) begin
	    addr = truncate(awfifo.first.addr);
	    id = truncate(awfifo.first.tag);
	 end
	 axiSlave.awaddr(addr);
	 axiSlave.awid(id);
	 axiSlave.awsize(axiBusSize(valueOf(dataWidth)));
	 axiSlave.awburst(2'b01);
	 axiSlave.awprot(3'b000);
	 axiSlave.awcache(4'b0011);
      endrule
      rule rl_awfifo if (axiSlave.awready() == 1);
	 let req <- toGet(awfifo).get();
	 wtagfifo.enq(req.tag);
      endrule
      rule rl_wvalid;
	 axiSlave.wvalid(pack(wfifo.notEmpty));
	 let wdata = 0;
	 if (wfifo.notEmpty)
	    wdata = wfifo.first.data;
	 axiSlave.wdata(wdata);
      endrule
      rule rl_wdata if (axiSlave.wready() == 1);
	 let md <- toGet(wfifo).get();
      endrule
      rule rl_bready;
	 axiSlave.bready(pack(wtagfifo.notEmpty && bfifo.notFull));
      endrule
      rule rl_done if (axiSlave.bvalid() == 1);
	 let tag <- toGet(wtagfifo).get();
	 bfifo.enq(tag);
      endrule

      interface PhysMemReadServer read_server;
	 interface Put readReq = toPut(arfifo);
	 interface Get readData = toGet(rfifo);
      endinterface
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = toPut(awfifo);
	 interface Put writeData = toPut(wfifo);
	 interface Get writeDone = toGet(bfifo);
      endinterface
   endmodule
endinstance

module mkMemReadClient#(Reg#(Bit#(32)) objId, Axi4MasterBits#(32,dataWidth,MemTagSize,Empty) m)(MemReadClient#(dataWidth));

   Wire#(Bit#(1)) arready <- mkDWire(0);
   Wire#(Bit#(1)) rvalid <- mkDWire(0);
   Wire#(Bit#(MemTagSize)) rid <- mkDWire(0);
   Wire#(Bit#(2)) rresp <- mkDWire(0);
   Wire#(Bit#(dataWidth)) rdata <- mkDWire(0);
   Wire#(Bit#(1)) rlast <- mkDWire(0);

   FIFOF#(MemRequest)          arfifo <- mkCFFIFOF();
   FIFOF#(MemData#(dataWidth))  rfifo <- mkCFFIFOF();

   rule rl_araddr if (m.arvalid() == 1);
      let addr = m.araddr();
      let burstLenBytes = (extend(m.arlen())+1)*fromInteger(valueOf(TDiv#(dataWidth,8)));
      arfifo.enq(MemRequest { sglId: objId, offset: extend(addr), burstLen: burstLenBytes, tag: extend(m.arid()) });
   endrule
   rule handshake_ar;
        m.arready(pack(arfifo.notFull()));
   endrule

   rule rl_rdata if (m.rready() == 1);
      let md <- toGet(rfifo).get();
      rdata <= md.data;
      rlast <= pack(md.last);
      rresp <= 0;
      rid <= truncate(md.tag);
   endrule
   rule handshake_rdata;
      m.rvalid(pack(rfifo.notEmpty()));
      m.rid(rid);
      m.rresp(rresp);
      m.rdata(rdata);
      m.rlast(rlast);
   endrule

   interface Get readReq = toGet(arfifo);
   interface Put readData = toPut(rfifo);
endmodule

module mkMemWriteClient#(Reg#(Bit#(32)) objId, Axi4MasterBits#(32,dataWidth,MemTagSize,Empty) m)(MemWriteClient#(dataWidth));

   Wire#(Bit#(1)) awready <- mkDWire(0);
   Wire#(Bit#(1)) wready <- mkDWire(0);
   Wire#(Bit#(1)) bvalid <- mkDWire(0);
   Wire#(Bit#(MemTagSize)) bid <- mkDWire(0);
   Wire#(Bit#(2)) bresp <- mkDWire(0);

   FIFOF#(MemRequest)       awfifo   <- mkCFFIFOF();
   FIFOF#(MemData#(dataWidth)) wfifo <- mkCFFIFOF();
   FIFOF#(Bit#(MemTagSize))    bfifo <- mkCFFIFOF();

   rule rl_awaddr if (m.awvalid() == 1);
      let addr = m.awaddr();
      let burstLenBytes = (extend(m.awlen())+1)*fromInteger(valueOf(TDiv#(dataWidth,8)));
      awfifo.enq(MemRequest { sglId: objId, offset: extend(addr), burstLen: burstLenBytes, tag: extend(m.awid()) });
   endrule
   rule handshake_awaddr;
      m.awready(pack(awfifo.notFull()));
   endrule

   rule rl_wdata if (m.wvalid() == 1);
      wfifo.enq(MemData { data: m.wdata(), last: unpack(m.wlast()), tag: extend(m.wid()) });
   endrule
   rule handshake_wdata;
      m.wready(pack(wfifo.notFull()));
   endrule

   rule rl_bresp if (m.bready() == 1);
      let tag <- toGet(bfifo).get();
      bresp <= 0;
      bid <= truncate(tag);
   endrule
   rule handshake_b;
        m.bvalid(pack(bfifo.notEmpty()));
        m.bid(bid);
        m.bresp(bresp);
   endrule

   interface Get writeReq = toGet(awfifo);
   interface Get writeData = toGet(wfifo);
   interface Put writeDone = toPut(bfifo);
endmodule

typedef AxiMasterBits#(32,32,12,Empty) Pps7Maxigp;
typedef AxiSlaveBits#(32,32,6,Empty) Pps7Saxigp;
typedef AxiSlaveBits#(32,64,6,HPType) Pps7Saxihp;
typedef AxiSlaveBits#(32,64,3,ACPType) Pps7Saxiacp;

// 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 Clocks::*;
import FIFOF::*;
import CFFIFO::*;
import GetPut::*;
import MemTypes::*;
import EHRM::*;

interface AxiMasterBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(1)     aresetn();
    method Bit#(tagWidth)     arid();
    method Bit#(4)     arlen();
    method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(2)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(tagWidth)     awid();
    method Bit#(4)     awlen();
    method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(2)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(tagWidth) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rid(Bit#(tagWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(tagWidth)     wid();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
    interface extraType   extra;
endinterface

interface HPType;
    method Bit#(3)     racount();
    method Bit#(8)     rcount();
    method Action      rdissuecap1en(Bit#(1) v);
    method Bit#(6)     wacount();
    method Bit#(8)     wcount();
    method Action      wrissuecap1en(Bit#(1) v);
endinterface

interface ACPType;
    method Action      aruser(Bit#(5) v);
    method Action      awuser(Bit#(5) v);
endinterface

interface AxiSlaveBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Action      araddr(Bit#(addrWidth) v);
    method Action      arburst(Bit#(2) v);
    method Action      arcache(Bit#(4) v);
    method Bit#(1)     aresetn();
    method Action      arid(Bit#(tagWidth) v);
    method Action      arlen(Bit#(4) v);
    method Action      arlock(Bit#(2) v);
    method Action      arprot(Bit#(3) v);
    method Action      arqos(Bit#(4) v);
    method Bit#(1)     arready();
    method Action      arsize(Bit#(2) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Action      awburst(Bit#(2) v);
    method Action      awcache(Bit#(4) v);
    method Action      awid(Bit#(tagWidth) v);
    method Action      awlen(Bit#(4) v);
    method Action      awlock(Bit#(2) v);
    method Action      awprot(Bit#(3) v);
    method Action      awqos(Bit#(4) v);
    method Bit#(1)     awready();
    method Action      awsize(Bit#(2) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(tagWidth)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Action      wid(Bit#(tagWidth) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(TDiv#(dataWidth,8)) v);
    method Action      wvalid(Bit#(1) v);
    method Bit#(tagWidth)     rid();
    interface extraType   extra;
endinterface

interface Axi4MasterBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(1)     aresetn();
    method Bit#(tagWidth)     arid();
    method Bit#(8)     arlen();
    method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(tagWidth)     awid();
    method Bit#(8)     awlen();
    method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(tagWidth) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rid(Bit#(tagWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(tagWidth)     wid();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
    interface extraType   extra;
endinterface

interface Axi4MasterUntaggedBits#(numeric type addrWidth, numeric type dataWidth);
    method Bit#(addrWidth)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(8)     arlen();
    //method Bit#(2)     arlock();
    method Bit#(3)     arprot();
    //method Bit#(4)     arqos();
    method Action      arready(Bit#(1) v);
    method Bit#(3)     arsize();
    method Bit#(1)     arvalid();
    method Bit#(addrWidth)     awaddr();
    method Bit#(2)     awburst();
    method Bit#(4)     awcache();
    method Bit#(8)     awlen();
    //method Bit#(2)     awlock();
    method Bit#(3)     awprot();
    //method Bit#(4)     awqos();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(dataWidth) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(dataWidth)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(TDiv#(dataWidth,8))     wstrb();
    method Bit#(1)     wvalid();
endinterface

typeclass ToAxi4MasterBits#(type atype, type btype);
   function atype toAxi4MasterBits(btype b);
endtypeclass

instance ToAxi4MasterBits#(Axi4MasterBits#(addrWidth,dataWidth,tagWidth,Empty), Axi4MasterUntaggedBits#(addrWidth,dataWidth));
function Axi4MasterBits#(addrWidth,dataWidth,tagWidth,Empty) toAxi4MasterBits(Axi4MasterUntaggedBits#(addrWidth,dataWidth) m);
   return (interface Axi4MasterBits#(addrWidth,dataWidth,tagWidth,Empty);
    method araddr = m.araddr;
      method arburst = m.arburst;
      method arcache = m.arcache;
      //method aresetn = no_reset;
      method Bit#(tagWidth)     arid(); return 0; endmethod
      method arlen = m.arlen;
      //method arlock = m.arlock;
      method arprot = m.arprot;
      //method arqos = m.arqos;
      method arready = m.arready;
      method arsize = m.arsize;
      method arvalid = m.arvalid;
      method awaddr = m.awaddr;
      method awburst = m.awburst;
      method awcache = m.awcache;
      method Bit#(tagWidth)     awid(); return 0; endmethod
      method awlen = m.awlen;
      //method awlock = m.awlock;
      method awprot = m.awprot;
      //method awqos = m.awqos;
      method awready = m.awready;
      method awsize = m.awsize;
      method awvalid = m.awvalid;
      method Action      bid(Bit#(tagWidth) v); endmethod
      method bready = m.bready;
      method bresp = m.bresp;
      method bvalid = m.bvalid;
      method rdata = m.rdata;
      method Action      rid(Bit#(tagWidth) v); endmethod
      method rlast = m.rlast;
      method rready = m.rready;
      method rresp = m.rresp;
      method rvalid = m.rvalid;
      method wdata = m.wdata;
      method Bit#(tagWidth)     wid(); return 0; endmethod
      method wlast = m.wlast;
      method wready = m.wready;
      method wstrb = m.wstrb;
      method wvalid = m.wvalid;
      interface extra = ?;
      endinterface);
endfunction
endinstance

interface Axi4SlaveBits#(numeric type addrWidth, numeric type dataWidth, numeric type tagWidth, type extraType);
    method Action      araddr(Bit#(addrWidth) v);
    method Action      arburst(Bit#(2) v);
    method Action      arcache(Bit#(4) v);
    method Bit#(1)     aresetn();
    method Action      arid(Bit#(tagWidth) v);
    method Action      arlen(Bit#(8) v);
    method Action      arlock(Bit#(2) v);
    method Action      arprot(Bit#(3) v);
    method Action      arqos(Bit#(4) v);
    method Bit#(1)     arready();
    method Action      arsize(Bit#(3) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Action      awburst(Bit#(2) v);
    method Action      awcache(Bit#(4) v);
    method Action      awid(Bit#(tagWidth) v);
    method Action      awlen(Bit#(8) v);
    method Action      awlock(Bit#(2) v);
    method Action      awprot(Bit#(3) v);
    method Action      awqos(Bit#(4) v);
    method Bit#(1)     awready();
    method Action      awsize(Bit#(3) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(tagWidth)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Action      wid(Bit#(tagWidth) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(TDiv#(dataWidth,8)) v);
    method Action      wvalid(Bit#(1) v);
    method Bit#(tagWidth)     rid();
    interface extraType   extra;
endinterface

interface Axi4SlaveLiteBits#(numeric type addrWidth, numeric type dataWidth);
    method Action      araddr(Bit#(addrWidth) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(addrWidth) v);
    method Bit#(1)     awready();
    method Action      awvalid(Bit#(1) v);
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(dataWidth)     rdata();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(dataWidth) v);
    method Bit#(1)     wready();
    method Action      wvalid(Bit#(1) v);
endinterface

typeclass ToAxi4SlaveBits#(type atype, type btype);
   function atype toAxi4SlaveBits(btype b);
endtypeclass

module mkAxiFifoF(FIFOF#(t)) provisos(Bits#(t, tSz));
  Ehr#(2, t) da <- mkEhr(?);
  Ehr#(2, Bool) va <- mkEhr(False);
  Ehr#(2, t) db <- mkEhr(?);
  Ehr#(2, Bool) vb <- mkEhr(False);

  rule canon if(vb[1] && !va[1]);
    da[1] <= db[1];
    va[1] <= True;
    vb[1] <= False;
  endrule

  method Bool notFull = !vb[0];

  method Action enq(t x) if(!vb[0]);
    db[0] <= x;
    vb[0] <= True;
  endmethod

  method Bool notEmpty = va[0];

  method Action deq if (va[0]);
    va[0] <= False;
  endmethod

  // no implicit guard, to simplify rule guards below
  method t first;
    return da[0];
  endmethod

  // conflicts with enq, deq, but we do not call it
  method Action clear;
    vb[0] <= False;
    va[0] <= False;
  endmethod
endmodule

typeclass MkPhysMemSlave#(type srctype, numeric type addrWidth, numeric type dataWidth);
   module mkPhysMemSlave#(srctype axiSlave)(PhysMemSlave#(addrWidth,dataWidth));
endtypeclass

instance MkPhysMemSlave#(Axi4SlaveLiteBits#(axiAddrWidth,dataWidth),addrWidth,dataWidth)
      provisos (Add#(axiAddrWidth,a__,addrWidth));
   module mkPhysMemSlave#(Axi4SlaveLiteBits#(axiAddrWidth,dataWidth) axiSlave)(PhysMemSlave#(addrWidth,dataWidth));
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) rfifo <- mkAxiFifoF();
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) wfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) bfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) rtagfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) wtagfifo <- mkAxiFifoF();

      rule rl_arvalid_araddr;
	 axiSlave.arvalid(pack(arfifo.notEmpty && rtagfifo.notFull));
	 let addr = 0;
	 if (arfifo.notEmpty)
	    addr = truncate(arfifo.first.addr);
	 axiSlave.araddr(addr);
      endrule
      rule rl_arfifo if (axiSlave.arready() == 1);
	 let req <- toGet(arfifo).get();
	 rtagfifo.enq(req.tag);
      endrule
      rule rl_rready;
	 axiSlave.rready(pack(rfifo.notFull && rtagfifo.notEmpty));
      endrule
      rule rl_rdata if (axiSlave.rvalid() == 1);
	 let rtag <- toGet(rtagfifo).get();
	 rfifo.enq(MemData { data: axiSlave.rdata(), tag: rtag } );
      endrule

      rule rl_awvalid_awaddr;
	 axiSlave.awvalid(pack(awfifo.notEmpty && wtagfifo.notFull));
	 let addr = 0;
	 if (awfifo.notEmpty)
	    addr = truncate(awfifo.first.addr);
	 axiSlave.awaddr(addr);
      endrule
      rule rl_awfifo if (axiSlave.awready() == 1);
	 let req <- toGet(awfifo).get();
	 wtagfifo.enq(req.tag);
      endrule
      rule rl_wvalid;
	 axiSlave.wvalid(pack(wfifo.notEmpty));
	 let wdata = 0;
	 if (wfifo.notEmpty)
	    wdata = wfifo.first.data;
	 axiSlave.wdata(wdata);
      endrule
      rule rl_wdata if (axiSlave.wready() == 1);
	 let md <- toGet(wfifo).get();
      endrule
      rule rl_bready;
	 axiSlave.bready(pack(wtagfifo.notEmpty && bfifo.notFull));
      endrule
      rule rl_done if (axiSlave.bvalid() == 1);
	 let tag <- toGet(wtagfifo).get();
	 bfifo.enq(tag);
      endrule

      interface PhysMemReadServer read_server;
	 interface Put readReq = toPut(arfifo);
	 interface Get readData = toGet(rfifo);
      endinterface
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = toPut(awfifo);
	 interface Put writeData = toPut(wfifo);
	 interface Get writeDone = toGet(bfifo);
      endinterface
   endmodule
endinstance

//FIXME burst transfers
instance MkPhysMemSlave#(Axi4SlaveBits#(axiAddrWidth,dataWidth,tagWidth,Empty),addrWidth,dataWidth)
      provisos (Add#(axiAddrWidth,a__,addrWidth));
   module mkPhysMemSlave#(Axi4SlaveBits#(axiAddrWidth,dataWidth,tagWidth,Empty) axiSlave)(PhysMemSlave#(addrWidth,dataWidth));
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) arfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) rfifo <- mkAxiFifoF();
      FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) awfifo <- mkAxiFifoF();
      FIFOF#(MemData#(dataWidth)) wfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) bfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) rtagfifo <- mkAxiFifoF();
      FIFOF#(Bit#(MemTagSize)) wtagfifo <- mkAxiFifoF();

      rule rl_arvalid_araddr;
	 axiSlave.arvalid(pack(arfifo.notEmpty && rtagfifo.notFull));
	 let addr = 0;
	 if (arfifo.notEmpty)
	    addr = truncate(arfifo.first.addr);
	 axiSlave.araddr(addr);
      endrule
      rule rl_arfifo if (axiSlave.arready() == 1);
	 let req <- toGet(arfifo).get();
	 rtagfifo.enq(req.tag);
      endrule
      rule rl_rready;
	 axiSlave.rready(pack(rfifo.notFull && rtagfifo.notEmpty));
      endrule
      rule rl_rdata if (axiSlave.rvalid() == 1);
	 let rtag <- toGet(rtagfifo).get();
	 rfifo.enq(MemData { data: axiSlave.rdata(), tag: rtag } );
      endrule

      rule rl_awvalid_awaddr;
	 axiSlave.awvalid(pack(awfifo.notEmpty && wtagfifo.notFull));
	 let addr = 0;
	 if (awfifo.notEmpty)
	    addr = truncate(awfifo.first.addr);
	 axiSlave.awaddr(addr);
      endrule
      rule rl_awfifo if (axiSlave.awready() == 1);
	 let req <- toGet(awfifo).get();
	 wtagfifo.enq(req.tag);
      endrule
      rule rl_wvalid;
	 axiSlave.wvalid(pack(wfifo.notEmpty));
	 let wdata = 0;
	 if (wfifo.notEmpty)
	    wdata = wfifo.first.data;
	 axiSlave.wdata(wdata);
      endrule
      rule rl_wdata if (axiSlave.wready() == 1);
	 let md <- toGet(wfifo).get();
      endrule
      rule rl_bready;
	 axiSlave.bready(pack(wtagfifo.notEmpty && bfifo.notFull));
      endrule
      rule rl_done if (axiSlave.bvalid() == 1);
	 let tag <- toGet(wtagfifo).get();
	 bfifo.enq(tag);
      endrule

      interface PhysMemReadServer read_server;
	 interface Put readReq = toPut(arfifo);
	 interface Get readData = toGet(rfifo);
      endinterface
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = toPut(awfifo);
	 interface Put writeData = toPut(wfifo);
	 interface Get writeDone = toGet(bfifo);
      endinterface
   endmodule
endinstance

module mkMemReadClient#(Reg#(Bit#(32)) objId, Axi4MasterBits#(32,dataWidth,MemTagSize,Empty) m)(MemReadClient#(dataWidth));

   Wire#(Bit#(1)) arready <- mkDWire(0);
   Wire#(Bit#(1)) rvalid <- mkDWire(0);
   Wire#(Bit#(MemTagSize)) rid <- mkDWire(0);
   Wire#(Bit#(2)) rresp <- mkDWire(0);
   Wire#(Bit#(dataWidth)) rdata <- mkDWire(0);
   Wire#(Bit#(1)) rlast <- mkDWire(0);

   FIFOF#(MemRequest)          arfifo <- mkCFFIFOF();
   FIFOF#(MemData#(dataWidth))  rfifo <- mkCFFIFOF();

   rule rl_araddr if (m.arvalid() == 1);
      let addr = m.araddr();
      let burstLenBytes = (extend(m.arlen())+1)*fromInteger(valueOf(TDiv#(dataWidth,8)));
      arfifo.enq(MemRequest { sglId: objId, offset: extend(addr), burstLen: burstLenBytes, tag: extend(m.arid()) });
   endrule
   rule handshake_ar;
        m.arready(pack(arfifo.notFull()));
   endrule

   rule rl_rdata if (m.rready() == 1);
      let md <- toGet(rfifo).get();
      rdata <= md.data;
      rlast <= pack(md.last);
      rresp <= 0;
      rid <= truncate(md.tag);
   endrule
   rule handshake_rdata;
      m.rvalid(pack(rfifo.notEmpty()));
      m.rid(rid);
      m.rresp(rresp);
      m.rdata(rdata);
      m.rlast(rlast);
   endrule

   interface Get readReq = toGet(arfifo);
   interface Put readData = toPut(rfifo);
endmodule

module mkMemWriteClient#(Reg#(Bit#(32)) objId, Axi4MasterBits#(32,dataWidth,MemTagSize,Empty) m)(MemWriteClient#(dataWidth));

   Wire#(Bit#(1)) awready <- mkDWire(0);
   Wire#(Bit#(1)) wready <- mkDWire(0);
   Wire#(Bit#(1)) bvalid <- mkDWire(0);
   Wire#(Bit#(MemTagSize)) bid <- mkDWire(0);
   Wire#(Bit#(2)) bresp <- mkDWire(0);

   FIFOF#(MemRequest)       awfifo   <- mkCFFIFOF();
   FIFOF#(MemData#(dataWidth)) wfifo <- mkCFFIFOF();
   FIFOF#(Bit#(MemTagSize))    bfifo <- mkCFFIFOF();

   rule rl_awaddr if (m.awvalid() == 1);
      let addr = m.awaddr();
      let burstLenBytes = (extend(m.awlen())+1)*fromInteger(valueOf(TDiv#(dataWidth,8)));
      awfifo.enq(MemRequest { sglId: objId, offset: extend(addr), burstLen: burstLenBytes, tag: extend(m.awid()) });
   endrule
   rule handshake_awaddr;
      m.awready(pack(awfifo.notFull()));
   endrule

   rule rl_wdata if (m.wvalid() == 1);
      wfifo.enq(MemData { data: m.wdata(), last: unpack(m.wlast()), tag: extend(m.wid()) });
   endrule
   rule handshake_wdata;
      m.wready(pack(wfifo.notFull()));
   endrule

   rule rl_bresp if (m.bready() == 1);
      let tag <- toGet(bfifo).get();
      bresp <= 0;
      bid <= truncate(tag);
   endrule
   rule handshake_b;
        m.bvalid(pack(bfifo.notEmpty()));
        m.bid(bid);
        m.bresp(bresp);
   endrule

   interface Get writeReq = toGet(awfifo);
   interface Get writeData = toGet(wfifo);
   interface Put writeDone = toPut(bfifo);
endmodule

typedef AxiMasterBits#(32,32,12,Empty) Pps7Maxigp;
typedef AxiSlaveBits#(32,32,6,Empty) Pps7Saxigp;
typedef AxiSlaveBits#(32,64,6,HPType) Pps7Saxihp;
typedef AxiSlaveBits#(32,64,3,ACPType) Pps7Saxiacp;


fix bug in ctrlmux

fix bug in ctrlmux

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

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

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

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

import Vector::*;
import GetPut::*;
import SpecialFIFOs::*;
import FIFO::*;

import AxiMasterSlave::*;
import Portal::*;
import Directory::*;

module mkInterruptMux#(Vector#(numPortals,Portal#(aw,_a,_b,_c)) portals) (ReadOnly#(Bool))

   provisos(Add#(nz, TLog#(numPortals), 4),
	    Add#(1, a__, numPortals));

   Vector#(numPortals, ReadOnly#(Bool)) inputs = map(getInterrupt, portals);

   function Bool my_read(ReadOnly#(Bool) x);
      return x._read;
   endfunction

   function Bool my_or(Bool a, Bool b);
      return a || b;
   endfunction

   method Bool _read;
      return fold(my_or,map(my_read,inputs));
   endmethod

endmodule

module mkAxiSlaveMux#(Vector#(1,         Portal#(aw,_a,_b,_c)) directories,
		      Vector#(numPortals,Portal#(aw,_a,_b,_c)) portals) (Axi3Slave#(_a,_b,_c))

   provisos(Add#(1,numPortals,numInputs),
	    Add#(1,numInputs,numIfcs),
	    Add#(nz, TLog#(numIfcs), 4));

   Axi3Slave#(_a,_b,_c) out_of_range <- mkAxi3SlaveOutOfRange;
   Vector#(numIfcs, Axi3Slave#(_a,_b,_c)) ifcs = append(append(map(getCtrl, directories),map(getCtrl, portals)),cons(out_of_range, nil));

   Reg#(Bit#(TLog#(numIfcs))) ws <- mkReg(0);
   Reg#(Bit#(TLog#(numIfcs))) rs <- mkReg(0);

   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TAdd#(3,aw));
   function Bit#(4) psel(Bit#(_a) a);
      return a[port_sel_high:port_sel_low];
   endfunction

   interface Put req_aw;
      method Action put(Axi3WriteRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) wsv = truncate(psel(req.address));
	 if (wsv > fromInteger(valueOf(numInputs)))
	    wsv = fromInteger(valueOf(numInputs));
	 ifcs[wsv].req_aw.put(req);
	 ws <= wsv;
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(_b,_c) wdata);
	 ifcs[ws].resp_write.put(wdata);
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(_c)) get();
	 let rv <- ifcs[ws].resp_b.get();
	 return rv;
      endmethod
   endinterface
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) rsv = truncate(psel(req.address));
	 if (rsv > fromInteger(valueOf(numInputs)))
	    rsv = fromInteger(valueOf(numInputs));
	 ifcs[rsv].req_ar.put(req);
	 rs <= rsv;
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(_b,_c)) get();
	 let rv <- ifcs[rs].resp_read.get();
	 return rv;
      endmethod
   endinterface
endmodule

module mkAxiSlaveMuxDbg#(Directory#(aw,_a,_b,_c) dir,
			 Vector#(numPortals,Portal#(aw,_a,_b,_c)) portals) (Axi3Slave#(_a,_b,_c))

   provisos(Add#(1,numPortals,numInputs),
	    Add#(1,numInputs,numIfcs),
	    Add#(nz, TLog#(numIfcs), 4));

   Vector#(1, Portal#(aw,_a,_b,_c)) directories = cons(dir.portalIfc,nil);

   Axi3Slave#(_a,_b,_c) out_of_range <- mkAxi3SlaveOutOfRange;
   Vector#(numIfcs, Axi3Slave#(_a,_b,_c)) ifcs = append(append(map(getCtrl, directories),map(getCtrl, portals)),cons(out_of_range, nil));

   Reg#(Bit#(TLog#(numIfcs))) ws <- mkReg(0);
   Reg#(Bit#(TLog#(numIfcs))) rs <- mkReg(0);

   Vector#(3,Reg#(Bit#(64))) writeIntervals <- replicateM(mkReg(0));
   Vector#(3,Reg#(Bit#(64))) readIntervals <- replicateM(mkReg(0));

   FIFO#(void) req_ar_fifo <- mkPipelineFIFO;
   FIFO#(void) req_aw_fifo <- mkPipelineFIFO;

   rule xferIntervals;
      dir.writeIntervals[0] <= writeIntervals[0];
      dir.writeIntervals[1] <= writeIntervals[1];
      dir.writeIntervals[2] <= writeIntervals[2];
      dir.readIntervals[0] <= readIntervals[0];
      dir.readIntervals[1] <= readIntervals[1];
      dir.readIntervals[2] <= readIntervals[2];
   endrule

   function Action latchWriteInterval;
      action
	 writeIntervals[2] <= writeIntervals[1];
	 writeIntervals[1] <= writeIntervals[0];
	 writeIntervals[0] <= truncate(dir.cycles);
      endaction
   endfunction

   function Action latchReadInterval;
      action
	 readIntervals[2] <= readIntervals[1];
	 readIntervals[1] <= readIntervals[0];
	 readIntervals[0] <= truncate(dir.cycles);
      endaction
   endfunction

   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TAdd#(3,aw));
   function Bit#(4) psel(Bit#(_a) a);
      return a[port_sel_high:port_sel_low];
   endfunction

   interface Put req_aw;
      method Action put(Axi3WriteRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) wsv = truncate(psel(req.address));
	 if (wsv > fromInteger(valueOf(numInputs)))
	    wsv = fromInteger(valueOf(numInputs));
	 ifcs[wsv].req_aw.put(req);
	 ws <= wsv;
	 req_aw_fifo.enq(?);
	 if (wsv > 0)
	    latchWriteInterval;
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(_b,_c) wdata);
	 ifcs[ws].resp_write.put(wdata);
	 req_aw_fifo.deq;
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(_c)) get();
	 let rv <- ifcs[ws].resp_b.get();
	 return rv;
      endmethod
   endinterface
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) rsv = truncate(psel(req.address));
	 if (rsv > fromInteger(valueOf(numInputs)))
	    rsv = fromInteger(valueOf(numInputs));
	 ifcs[rsv].req_ar.put(req);
	 rs <= rsv;
	 req_ar_fifo.enq(?);
	 if (rsv > 0)
	    latchReadInterval;
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(_b,_c)) get();
	 let rv <- ifcs[rs].resp_read.get();
	 req_ar_fifo.deq;
	 return rv;
      endmethod
   endinterface

endmodule

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

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

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

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

import Vector::*;
import GetPut::*;

import AxiMasterSlave::*;
import Portal::*;
import Directory::*;

module mkInterruptMux#(Vector#(numPortals,Portal#(aw,_a,_b,_c)) portals) (ReadOnly#(Bool))

   provisos(Add#(nz, TLog#(numPortals), 4),
	    Add#(1, a__, numPortals));

   Vector#(numPortals, ReadOnly#(Bool)) inputs = map(getInterrupt, portals);

   function Bool my_read(ReadOnly#(Bool) x);
      return x._read;
   endfunction

   function Bool my_or(Bool a, Bool b);
      return a || b;
   endfunction

   method Bool _read;
      return fold(my_or,map(my_read,inputs));
   endmethod

endmodule

module mkAxiSlaveMux#(Vector#(1,         Portal#(aw,_a,_b,_c)) directories,
		      Vector#(numPortals,Portal#(aw,_a,_b,_c)) portals) (Axi3Slave#(_a,_b,_c))

   provisos(Add#(1,numPortals,numInputs),
	    Add#(1,numInputs,numIfcs),
	    Add#(nz, TLog#(numIfcs), 4));

   Axi3Slave#(_a,_b,_c) out_of_range <- mkAxi3SlaveOutOfRange;
   Vector#(numIfcs, Axi3Slave#(_a,_b,_c)) ifcs = append(append(map(getCtrl, directories),map(getCtrl, portals)),cons(out_of_range, nil));

   Reg#(Bit#(TLog#(numIfcs))) ws <- mkReg(0);
   Reg#(Bit#(TLog#(numIfcs))) rs <- mkReg(0);

   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TAdd#(3,aw));
   function Bit#(4) psel(Bit#(_a) a);
      return a[port_sel_high:port_sel_low];
   endfunction

   interface Put req_aw;
      method Action put(Axi3WriteRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) wsv = truncate(psel(req.address));
	 if (wsv > fromInteger(valueOf(numInputs)))
	    wsv = fromInteger(valueOf(numInputs));
	 ifcs[wsv].req_aw.put(req);
	 ws <= wsv;
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(_b,_c) wdata);
	 ifcs[ws].resp_write.put(wdata);
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(_c)) get();
	 let rv <- ifcs[ws].resp_b.get();
	 return rv;
      endmethod
   endinterface
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) rsv = truncate(psel(req.address));
	 if (rsv > fromInteger(valueOf(numInputs)))
	    rsv = fromInteger(valueOf(numInputs));
	 ifcs[rsv].req_ar.put(req);
	 rs <= rsv;
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(_b,_c)) get();
	 let rv <- ifcs[rs].resp_read.get();
	 return rv;
      endmethod
   endinterface
endmodule

module mkAxiSlaveMuxDbg#(Directory#(aw,_a,_b,_c) dir,
			 Vector#(numPortals,Portal#(aw,_a,_b,_c)) portals) (Axi3Slave#(_a,_b,_c))

   provisos(Add#(1,numPortals,numInputs),
	    Add#(1,numInputs,numIfcs),
	    Add#(nz, TLog#(numIfcs), 4));

   Vector#(1, Portal#(aw,_a,_b,_c)) directories = cons(dir.portalIfc,nil);

   Axi3Slave#(_a,_b,_c) out_of_range <- mkAxi3SlaveOutOfRange;
   Vector#(numIfcs, Axi3Slave#(_a,_b,_c)) ifcs = append(append(map(getCtrl, directories),map(getCtrl, portals)),cons(out_of_range, nil));

   Reg#(Bit#(TLog#(numIfcs))) ws <- mkReg(0);
   Reg#(Bit#(TLog#(numIfcs))) rs <- mkReg(0);

   Vector#(3,Reg#(Bit#(64))) writeIntervals <- replicateM(mkReg(0));
   Vector#(3,Reg#(Bit#(64))) readIntervals <- replicateM(mkReg(0));

   rule xferIntervals;
      dir.writeIntervals[0] <= writeIntervals[0];
      dir.writeIntervals[1] <= writeIntervals[1];
      dir.writeIntervals[2] <= writeIntervals[2];
      dir.readIntervals[0] <= readIntervals[0];
      dir.readIntervals[1] <= readIntervals[1];
      dir.readIntervals[2] <= readIntervals[2];
   endrule

   function Action latchWriteInterval;
      action
	 writeIntervals[2] <= writeIntervals[1];
	 writeIntervals[1] <= writeIntervals[0];
	 writeIntervals[0] <= truncate(dir.cycles);
      endaction
   endfunction

   function Action latchReadInterval;
      action
	 readIntervals[2] <= readIntervals[1];
	 readIntervals[1] <= readIntervals[0];
	 readIntervals[0] <= truncate(dir.cycles);
      endaction
   endfunction

   let port_sel_low = valueOf(aw);
   let port_sel_high = valueOf(TAdd#(3,aw));
   function Bit#(4) psel(Bit#(_a) a);
      return a[port_sel_high:port_sel_low];
   endfunction

   interface Put req_aw;
      method Action put(Axi3WriteRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) wsv = truncate(psel(req.address));
	 if (wsv > fromInteger(valueOf(numInputs)))
	    wsv = fromInteger(valueOf(numInputs));
	 ifcs[wsv].req_aw.put(req);
	 ws <= wsv;
	 if (wsv > 0)
	    latchWriteInterval;
      endmethod
   endinterface
   interface Put resp_write;
      method Action put(Axi3WriteData#(_b,_c) wdata);
	 ifcs[ws].resp_write.put(wdata);
      endmethod
   endinterface
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(_c)) get();
	 let rv <- ifcs[ws].resp_b.get();
	 return rv;
      endmethod
   endinterface
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(_a,_c) req);
	 Bit#(TLog#(numIfcs)) rsv = truncate(psel(req.address));
	 if (rsv > fromInteger(valueOf(numInputs)))
	    rsv = fromInteger(valueOf(numInputs));
	 ifcs[rsv].req_ar.put(req);
	 rs <= rsv;
	 if (rsv > 0)
	    latchReadInterval;
      endmethod
   endinterface
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(_b,_c)) get();
	 let rv <- ifcs[rs].resp_read.get();
	 return rv;
      endmethod
   endinterface

endmodule


add in 'tee' for bluescope datain (but disabled)

// 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 FIFO::*;
import GetPut::*;
import Connectable :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;

import GetPutWithClocks :: *;
import Zynq::*;
import Imageon::*;
import HDMI::*;
import AxiDMA::*;
import BlueScope::*;
import SensorToVideo::*;

interface CoreIndication;
    method Action spi_control_value(Bit#(32) v);
    method Action iserdes_control_value(Bit#(32) v);
    method Action decoder_control_value(Bit#(32) v);
    method Action triggen_control_value(Bit#(32) v);
    method Action spi_rxfifo_value(Bit#(32) v);
    method Action debugind(Bit#(32) v);
endinterface

interface CoreRequest;
    method Action set_spi_control(Bit#(32) v);
    method Action get_spi_control();
    method Action set_iserdes_control(Bit#(32) v);
    method Action get_iserdes_control();
    method Action set_decoder_control(Bit#(32) v);
    method Action get_decoder_control();
    method Action set_triggen_control(Bit#(32) v);
    method Action get_triggen_control();

    method Action set_host_vita_reset(Bit#(1) v);
    method Action set_host_oe(Bit#(1) v);

    method Action set_spi_reset(Bit#(1) v);
    method Action set_spi_timing(Bit#(16) v);
    method Action put_spi_txfifo(Bit#(32) v);
    method Action get_spi_rxfifo();

    method Action set_serdes_reset(Bit#(1) v);
    method Action set_serdes_auto_align(Bit#(1) v);
    method Action set_serdes_align_start(Bit#(1) v);
    method Action set_serdes_fifo_enable(Bit#(1) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Action set_decoder_reset(Bit#(1) v);
    method Action set_decoder_enable(Bit#(1) v);
    method Action set_decoder_code_ls(Bit#(10) v);
    method Action set_decoder_code_le(Bit#(10) v);
    method Action set_decoder_code_fs(Bit#(10) v);
    method Action set_decoder_code_fe(Bit#(10) v);
    method Action set_decoder_code_bl(Bit#(10) v);
    method Action set_decoder_code_img(Bit#(10) v);
    method Action set_trigger_enable(Bit#(3) v);
    method Action set_trigger_default_freq(Bit#(32) v);
    method Action set_trigger_cnt_trigger0high(Bit#(32) v);
    method Action set_trigger_cnt_trigger0low(Bit#(32) v);
    method Action set_syncgen_delay(Bit#(16) v);
    method Action set_syncgen_hactive(Bit#(16) v);
    method Action set_syncgen_hfporch(Bit#(16) v);
    method Action set_syncgen_hsync(Bit#(16) v);
    method Action set_syncgen_hbporch(Bit#(16) v);
    method Action set_syncgen_vactive(Bit#(16) v);
    method Action set_syncgen_vfporch(Bit#(16) v);
    method Action set_syncgen_vsync(Bit#(16) v);
    method Action set_syncgen_vbporch(Bit#(16) v);
    method Action set_debugreq(Bit#(32) v);
    method Action get_debugind();
endinterface

interface ImageCaptureIndication;
    interface CoreIndication coreIndication;
    interface BlueScopeIndication bsIndication;
endinterface

interface ImageCaptureRequest;
   interface CoreRequest coreRequest;
   interface BlueScopeRequest bsRequest;
   interface ImageonVita imageon;
   interface ImageonSensorData sensor_data;
   interface HDMI hdmi;
endinterface

module mkImageCaptureRequest#(Clock imageon_clock, Clock hdmi_clock,
    ImageCaptureIndication indication)(ImageCaptureRequest) provisos (Bits#(XsviData,xsviDataWidth));

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Reset imageon_reset <- mkAsyncReset(2, defaultReset, imageon_clock);
    Reset hdmi_reset <- mkAsyncReset(2, defaultReset, hdmi_clock);

    ImageonVitaController imageonVita <- mkImageonVitaController();
    ImageonControl control = imageonVita.control;
    ImageonXsviFromSensor xsviFromSensor <- mkImageonXsviFromSensor(imageon_clock, imageon_reset, clocked_by hdmi_clock, reset_by hdmi_reset);

    AxiDMA dma <- mkAxiDMA;
    WriteChan dma_debug_write_chan = dma.write.writeChannels[1];
    BlueScopeInternal bsi <- mkSyncBlueScopeInternal(32, dma_debug_write_chan, indication.bsIndication,
					             hdmi_clock, hdmi_reset, defaultClock, defaultReset);

    SensorToVideo converter <- mkSensorToVideo(clocked_by hdmi_clock, reset_by hdmi_reset);
    HdmiOut hdmiOut <- mkHdmiOut(clocked_by hdmi_clock, reset_by hdmi_reset);

    mkConnection(control.rxfifo_response.get, indication.coreIndication.spi_rxfifo_value);
    // hdmi clock domain
    //mkConnection(xsviFromSensor.out, converter.in);
    rule xsviConnection;
        let xsvi <- xsviFromSensor.out.get();
        //bsi.dataIn(extend(pack(xsvi)), extend(pack(xsvi)));
        converter.in.put(xsvi);
    endrule
    // hdmi clock domain
    mkConnection(converter.out, hdmiOut.rgb);

    interface CoreRequest coreRequest;
    method Action set_spi_control(Bit#(32) v);
        control.set_spi_control(v);
    endmethod
    method Action get_spi_control();
        indication.coreIndication.spi_control_value(control.get_spi_control());
    endmethod

    method Action set_iserdes_control(Bit#(32) v);
        control.set_iserdes_control(v);
    endmethod
    method Action get_iserdes_control();
        indication.coreIndication.iserdes_control_value(control.get_iserdes_control());
    endmethod

    method Action set_decoder_control(Bit#(32) v);
        control.set_decoder_control(v);
    endmethod
    method Action get_decoder_control();
        indication.coreIndication.decoder_control_value(control.get_decoder_control());
    endmethod

    method Action set_triggen_control(Bit#(32) v);
        control.set_triggen_control(v);
    endmethod
    method Action get_triggen_control();
        indication.coreIndication.triggen_control_value(control.get_triggen_control());
    endmethod

    method Action set_host_vita_reset(Bit#(1) v);
        control.set_host_vita_reset(v);
    endmethod
    method Action set_host_oe(Bit#(1) v);
        control.set_host_oe(v);
    endmethod

    method Action set_spi_reset(Bit#(1) v);
        control.set_spi_reset(v);
    endmethod
    method Action set_spi_timing(Bit#(16) v);
        control.set_spi_timing(v);
    endmethod
    method Action put_spi_txfifo(Bit#(32) v);
        control.txfifo.put(v);
    endmethod
    method Action get_spi_rxfifo();
        control.rxfifo_request.put(32'hABBAABBA);
    endmethod

    method Action set_serdes_reset(Bit#(1) v);
        control.set_serdes_reset(v);
    endmethod
    method Action set_serdes_auto_align(Bit#(1) v);
        control.set_serdes_auto_align(v);
    endmethod
    method Action set_serdes_align_start(Bit#(1) v);
        control.set_serdes_align_start(v);
    endmethod
    method Action set_serdes_fifo_enable(Bit#(1) v);
        control.set_serdes_fifo_enable(v);
    endmethod
    method Action set_serdes_manual_tap(Bit#(10) v);
        control.set_serdes_manual_tap(v);
    endmethod
    method Action set_serdes_training(Bit#(10) v);
        control.set_serdes_training(v);
    endmethod
    method Action set_decoder_reset(Bit#(1) v);
        control.set_decoder_reset(v);
    endmethod
    method Action set_decoder_enable(Bit#(1) v);
        control.set_decoder_enable(v);
    endmethod
    method Action set_decoder_code_ls(Bit#(10) v);
        control.set_decoder_code_ls(v);
    endmethod
    method Action set_decoder_code_le(Bit#(10) v);
        control.set_decoder_code_le(v);
    endmethod
    method Action set_decoder_code_fs(Bit#(10) v);
        control.set_decoder_code_fs(v);
    endmethod
    method Action set_decoder_code_fe(Bit#(10) v);
        control.set_decoder_code_fe(v);
    endmethod
    method Action set_decoder_code_bl(Bit#(10) v);
        control.set_decoder_code_bl(v);
    endmethod
    method Action set_decoder_code_img(Bit#(10) v);
        control.set_decoder_code_img(v);
    endmethod
    method Action set_trigger_enable(Bit#(3) v);
        control.set_trigger_enable(v);
    endmethod
    method Action set_trigger_default_freq(Bit#(32) v);
        control.set_trigger_default_freq(v);
    endmethod
    method Action set_trigger_cnt_trigger0high(Bit#(32) v);
        control.set_trigger_cnt_trigger0high(v);
    endmethod
    method Action set_trigger_cnt_trigger0low(Bit#(32) v);
        control.set_trigger_cnt_trigger0low(v);
    endmethod
    method Action set_syncgen_delay(Bit#(16) v);
        control.set_syncgen_delay(v);
    endmethod
    method Action set_syncgen_hactive(Bit#(16) v);
        control.set_syncgen_hactive(v);
    endmethod
    method Action set_syncgen_hfporch(Bit#(16) v);
        control.set_syncgen_hfporch(v);
    endmethod
    method Action set_syncgen_hsync(Bit#(16) v);
        control.set_syncgen_hsync(v);
    endmethod
    method Action set_syncgen_hbporch(Bit#(16) v);
        control.set_syncgen_hbporch(v);
    endmethod
    method Action set_syncgen_vactive(Bit#(16) v);
        control.set_syncgen_vactive(v);
    endmethod
    method Action set_syncgen_vfporch(Bit#(16) v);
        control.set_syncgen_vfporch(v);
    endmethod
    method Action set_syncgen_vsync(Bit#(16) v);
        control.set_syncgen_vsync(v);
    endmethod
    method Action set_syncgen_vbporch(Bit#(16) v);
        control.set_syncgen_vbporch(v);
    endmethod
    method Action set_debugreq(Bit#(32) v);
        control.set_debugreq(v);
    endmethod
    method Action get_debugind();
        indication.coreIndication.debugind(control.get_debugind());
    endmethod

    endinterface
   interface BlueScopeRequest bsRequest = bsi.requestIfc;
   interface ImageonVita imageon = imageonVita.host;
   interface ImageonSensorData sensor_data = xsviFromSensor.in;
   interface HDMI hdmi = hdmiOut.hdmi;
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 FIFO::*;
import GetPut::*;
import Connectable :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;

import GetPutWithClocks :: *;
import Zynq::*;
import Imageon::*;
import HDMI::*;
import AxiDMA::*;
import BlueScope::*;
import SensorToVideo::*;

interface CoreIndication;
    method Action spi_control_value(Bit#(32) v);
    method Action iserdes_control_value(Bit#(32) v);
    method Action decoder_control_value(Bit#(32) v);
    method Action triggen_control_value(Bit#(32) v);
    method Action spi_rxfifo_value(Bit#(32) v);
    method Action debugind(Bit#(32) v);
endinterface

interface CoreRequest;
    method Action set_spi_control(Bit#(32) v);
    method Action get_spi_control();
    method Action set_iserdes_control(Bit#(32) v);
    method Action get_iserdes_control();
    method Action set_decoder_control(Bit#(32) v);
    method Action get_decoder_control();
    method Action set_triggen_control(Bit#(32) v);
    method Action get_triggen_control();

    method Action set_host_vita_reset(Bit#(1) v);
    method Action set_host_oe(Bit#(1) v);

    method Action set_spi_reset(Bit#(1) v);
    method Action set_spi_timing(Bit#(16) v);
    method Action put_spi_txfifo(Bit#(32) v);
    method Action get_spi_rxfifo();

    method Action set_serdes_reset(Bit#(1) v);
    method Action set_serdes_auto_align(Bit#(1) v);
    method Action set_serdes_align_start(Bit#(1) v);
    method Action set_serdes_fifo_enable(Bit#(1) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Action set_decoder_reset(Bit#(1) v);
    method Action set_decoder_enable(Bit#(1) v);
    method Action set_decoder_code_ls(Bit#(10) v);
    method Action set_decoder_code_le(Bit#(10) v);
    method Action set_decoder_code_fs(Bit#(10) v);
    method Action set_decoder_code_fe(Bit#(10) v);
    method Action set_decoder_code_bl(Bit#(10) v);
    method Action set_decoder_code_img(Bit#(10) v);
    method Action set_trigger_enable(Bit#(3) v);
    method Action set_trigger_default_freq(Bit#(32) v);
    method Action set_trigger_cnt_trigger0high(Bit#(32) v);
    method Action set_trigger_cnt_trigger0low(Bit#(32) v);
    method Action set_syncgen_delay(Bit#(16) v);
    method Action set_syncgen_hactive(Bit#(16) v);
    method Action set_syncgen_hfporch(Bit#(16) v);
    method Action set_syncgen_hsync(Bit#(16) v);
    method Action set_syncgen_hbporch(Bit#(16) v);
    method Action set_syncgen_vactive(Bit#(16) v);
    method Action set_syncgen_vfporch(Bit#(16) v);
    method Action set_syncgen_vsync(Bit#(16) v);
    method Action set_syncgen_vbporch(Bit#(16) v);
    method Action set_debugreq(Bit#(32) v);
    method Action get_debugind();
endinterface

interface ImageCaptureIndication;
    interface CoreIndication coreIndication;
    interface BlueScopeIndication bsIndication;
endinterface

interface ImageCaptureRequest;
   interface CoreRequest coreRequest;
   interface BlueScopeRequest bsRequest;
   interface ImageonVita imageon;
   interface ImageonSensorData sensor_data;
   interface HDMI hdmi;
endinterface

module mkImageCaptureRequest#(Clock imageon_clock, Clock hdmi_clock,
    ImageCaptureIndication indication)(ImageCaptureRequest) provisos (Bits#(XsviData,xsviDataWidth));

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Reset imageon_reset <- mkAsyncReset(2, defaultReset, imageon_clock);
    Reset hdmi_reset <- mkAsyncReset(2, defaultReset, hdmi_clock);

    ImageonVitaController imageonVita <- mkImageonVitaController();
    ImageonControl control = imageonVita.control;
    ImageonXsviFromSensor xsviFromSensor <- mkImageonXsviFromSensor(imageon_clock, imageon_reset, clocked_by hdmi_clock, reset_by hdmi_reset);

    AxiDMA dma <- mkAxiDMA;
    WriteChan dma_debug_write_chan = dma.write.writeChannels[1];
    BlueScopeInternal bsi <- mkSyncBlueScopeInternal(32, dma_debug_write_chan, indication.bsIndication,
					             hdmi_clock, hdmi_reset, defaultClock, defaultReset);

    SensorToVideo converter <- mkSensorToVideo(clocked_by hdmi_clock, reset_by hdmi_reset);
    HdmiOut hdmiOut <- mkHdmiOut(clocked_by hdmi_clock, reset_by hdmi_reset);

    mkConnection(control.rxfifo_response.get, indication.coreIndication.spi_rxfifo_value);
    // hdmi clock domain
    mkConnection(xsviFromSensor.out, converter.in);
    // hdmi clock domain
    mkConnection(converter.out, hdmiOut.rgb);

    interface CoreRequest coreRequest;
    method Action set_spi_control(Bit#(32) v);
        control.set_spi_control(v);
    endmethod
    method Action get_spi_control();
        indication.coreIndication.spi_control_value(control.get_spi_control());
    endmethod

    method Action set_iserdes_control(Bit#(32) v);
        control.set_iserdes_control(v);
    endmethod
    method Action get_iserdes_control();
        indication.coreIndication.iserdes_control_value(control.get_iserdes_control());
    endmethod

    method Action set_decoder_control(Bit#(32) v);
        control.set_decoder_control(v);
    endmethod
    method Action get_decoder_control();
        indication.coreIndication.decoder_control_value(control.get_decoder_control());
    endmethod

    method Action set_triggen_control(Bit#(32) v);
        control.set_triggen_control(v);
    endmethod
    method Action get_triggen_control();
        indication.coreIndication.triggen_control_value(control.get_triggen_control());
    endmethod

    method Action set_host_vita_reset(Bit#(1) v);
        control.set_host_vita_reset(v);
    endmethod
    method Action set_host_oe(Bit#(1) v);
        control.set_host_oe(v);
    endmethod

    method Action set_spi_reset(Bit#(1) v);
        control.set_spi_reset(v);
    endmethod
    method Action set_spi_timing(Bit#(16) v);
        control.set_spi_timing(v);
    endmethod
    method Action put_spi_txfifo(Bit#(32) v);
        control.txfifo.put(v);
    endmethod
    method Action get_spi_rxfifo();
        control.rxfifo_request.put(32'hABBAABBA);
    endmethod

    method Action set_serdes_reset(Bit#(1) v);
        control.set_serdes_reset(v);
    endmethod
    method Action set_serdes_auto_align(Bit#(1) v);
        control.set_serdes_auto_align(v);
    endmethod
    method Action set_serdes_align_start(Bit#(1) v);
        control.set_serdes_align_start(v);
    endmethod
    method Action set_serdes_fifo_enable(Bit#(1) v);
        control.set_serdes_fifo_enable(v);
    endmethod
    method Action set_serdes_manual_tap(Bit#(10) v);
        control.set_serdes_manual_tap(v);
    endmethod
    method Action set_serdes_training(Bit#(10) v);
        control.set_serdes_training(v);
    endmethod
    method Action set_decoder_reset(Bit#(1) v);
        control.set_decoder_reset(v);
    endmethod
    method Action set_decoder_enable(Bit#(1) v);
        control.set_decoder_enable(v);
    endmethod
    method Action set_decoder_code_ls(Bit#(10) v);
        control.set_decoder_code_ls(v);
    endmethod
    method Action set_decoder_code_le(Bit#(10) v);
        control.set_decoder_code_le(v);
    endmethod
    method Action set_decoder_code_fs(Bit#(10) v);
        control.set_decoder_code_fs(v);
    endmethod
    method Action set_decoder_code_fe(Bit#(10) v);
        control.set_decoder_code_fe(v);
    endmethod
    method Action set_decoder_code_bl(Bit#(10) v);
        control.set_decoder_code_bl(v);
    endmethod
    method Action set_decoder_code_img(Bit#(10) v);
        control.set_decoder_code_img(v);
    endmethod
    method Action set_trigger_enable(Bit#(3) v);
        control.set_trigger_enable(v);
    endmethod
    method Action set_trigger_default_freq(Bit#(32) v);
        control.set_trigger_default_freq(v);
    endmethod
    method Action set_trigger_cnt_trigger0high(Bit#(32) v);
        control.set_trigger_cnt_trigger0high(v);
    endmethod
    method Action set_trigger_cnt_trigger0low(Bit#(32) v);
        control.set_trigger_cnt_trigger0low(v);
    endmethod
    method Action set_syncgen_delay(Bit#(16) v);
        control.set_syncgen_delay(v);
    endmethod
    method Action set_syncgen_hactive(Bit#(16) v);
        control.set_syncgen_hactive(v);
    endmethod
    method Action set_syncgen_hfporch(Bit#(16) v);
        control.set_syncgen_hfporch(v);
    endmethod
    method Action set_syncgen_hsync(Bit#(16) v);
        control.set_syncgen_hsync(v);
    endmethod
    method Action set_syncgen_hbporch(Bit#(16) v);
        control.set_syncgen_hbporch(v);
    endmethod
    method Action set_syncgen_vactive(Bit#(16) v);
        control.set_syncgen_vactive(v);
    endmethod
    method Action set_syncgen_vfporch(Bit#(16) v);
        control.set_syncgen_vfporch(v);
    endmethod
    method Action set_syncgen_vsync(Bit#(16) v);
        control.set_syncgen_vsync(v);
    endmethod
    method Action set_syncgen_vbporch(Bit#(16) v);
        control.set_syncgen_vbporch(v);
    endmethod
    method Action set_debugreq(Bit#(32) v);
        control.set_debugreq(v);
    endmethod
    method Action get_debugind();
        indication.coreIndication.debugind(control.get_debugind());
    endmethod

    endinterface
   interface BlueScopeRequest bsRequest = bsi.requestIfc;
   interface ImageonVita imageon = imageonVita.host;
   interface ImageonSensorData sensor_data = xsviFromSensor.in;
   interface HDMI hdmi = hdmiOut.hdmi;
endmodule


colocando FIFOs JTAG para testes

colocando FIFOs JTAG para testes

import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import Connectable::*;
import SysConfig::*;
import AsyncPulseSync::*;
import StatusLED::*;
import CycleCounter::*;
import ProgrammableCycleCounter::*;
import AvalonSlave::*;
import InterruptSender::*;
import JtagGetPut::*;

typedef Tuple2#(Bit#(NumFlags), TimeStamp) AcqFifoContents;

interface AcqSys;
	(* prefix="" *)
	interface InterruptSenderWires irqWires;
	(* prefix="" *)
	interface AvalonSlaveWires#(AvalonAddrSize, AvalonDataSize) avalonWires;
	(* prefix="" *)
	interface StatusLEDWires ledWires;
	(* prefix="CH" *)
	interface Vector#(NumInputs, AcqIn) inputs;
	(* always_ready, prefix="", result="STIM" *)
	method Stim stimuli;
endinterface

(* synthesize, clock_prefix="clk", reset_prefix="reset_n" *)
module mkAcqSys(AcqSys);
	AvalonSlave#(AvalonAddrSize, AvalonDataSize) avalon <- mkAvalonSlave;

	Vector#(NumInputs, SyncPulseIfc) inSyncs <- replicateM(mkAsyncPulseSync);
	Bit#(NumInputs) syncedIn = fromPulseVector(inSyncs);

	Array#(Reg#(Stim)) stimOut <- mkCReg(3, 0);
	CycleCounter#(CyclesStimRate) stimRate <- mkCycleCounter;
	Reg#(Bool) wordMatched <- mkReg(False);
	Bit#(NumFlags) flagIn = {wordMatched?1'b1:1'b0, stimRate.ticked?1'b1:1'b0, syncedIn};

	CycleCounter#(CyclesResolution) cycleCounter <- mkCycleCounter;
	StatusLED#(3) led <- mkStatusLED(flagIn, cycleCounter.ticked);
	Reg#(Bool) acqStarted <- mkReg(False);
	Reg#(TimeStamp) timestamp <- mkReg(0);
	Array#(Reg#(Bit#(NumFlags))) channelFlags <- mkCReg(2, 0);

	FIFOF#(AcqFifoContents) acqFifo <- mkSizedFIFOF(2*valueOf(NumFlags));
	RWire#(AcqFifoContents) acqFifoFirst <- mkRWire;
	FIFOF#(Stim) stimFifo <- mkFIFOF;

	BRAM2Port#(StimMemAddr, Stim) stimMem <- mkBRAM2Server(defaultValue);
	FIFOF#(void) stimMemPendRead <- mkFIFOF;  // to enforce order on responses
	Reg#(Bit#(TAdd#(StimMemAddrSize, 1))) stimMemSize <- mkReg(0);
	Reg#(Bit#(TAdd#(StimMemAddrSize, 1))) stimIndex <- mkReg(0);
	FIFOF#(Stim) stimFromMem <- mkFIFOF;

	ProgrammableCycleCounter#(AvalonDataSize) binBoundary <-
		mkProgrammableCycleCounter(fromInteger(defaultWordPeriod));
	Array#(Reg#(Bit#(1))) wordBit <- mkCReg(2, 0);
	Array#(Reg#(Word)) word <- mkCReg(2, 0);
	Reg#(Word) wordToMatch <- mkReg(32'hFFFFFFFF);
	Reg#(Word) wordMask <- mkReg(0);

	Get#(StimMemAddr) jtag_addr <- mkJtagGet("ADDR", mkFIFOF);
	Put#(Stim) jtag_data <- mkJtagPut("DATA", mkFIFOF);

	//mkConnection(stimMem.portA.response, toPut(stimFromMem));
    /*(* fire_when_enabled *)
    rule askshjasgsahsahgh;
        let data <- stimMem.portA.response.get;
        stimFromMem.enq(data);
    endrule*/

	(* fire_when_enabled *)
	rule peekAcqFifo;
		acqFifoFirst.wset(acqFifo.first);
	endrule

	(* fire_when_enabled *)
	rule answerStimMemRead;
		let resp <- stimMem.portB.response.get;
		avalon.busClient.response.put(extend(resp));
		stimMemPendRead.deq;
	endrule

	rule handleCmd(!stimMemPendRead.notEmpty);
		let cmd <- avalon.busClient.request.get;
		(*split*)
		if (cmd.addr[stimMemAddrSize] == 1'b0) begin
			(*split*)
			case (cmd) matches
				// Register @0x00: Enable/disable acquisition.
				tagged AvalonRequest{addr: 0, data: .x, command: Write}:
					action
						acqStarted <= x != 0;
						(*split*)
						if(x == 0) begin
							led.errorClear;
							acqFifo.clear;
							stimFifo.clear;
							//word[1] <= 0;
							//stimMemSize <= 0;
							//stimOut[2] <= 0;
						end
					endaction
				tagged AvalonRequest{addr: 0, data: .*, command: Read}:
					avalon.busClient.response.put(acqStarted ? 1 : 0);
				// Register @0x04: Read flags from the FIFO. MSB is zero if data is valid.
				tagged AvalonRequest{addr: 1, data: .*, command: Read}:
					action
						Bit#(NumFlags) flags = tpl_1(fromMaybe(tuple2(0,0), acqFifoFirst.wget));
						Bit#(TSub#(AvalonDataSize, 1)) extFlags = extend(flags);
						Bit#(1) invalidFlag = isValid(acqFifoFirst.wget) ? 0 : 1;
						avalon.busClient.response.put({invalidFlag, extFlags});
					endaction
				// Register @0x08: Read timestamp from the FIFO. WARNING: may block.
				tagged AvalonRequest{addr: 2, data: .*, command: Read}:
					action
						TimeStamp tstamp = tpl_2(acqFifo.first);
						avalon.busClient.response.put(tstamp);
						acqFifo.deq;
					endaction
				// Register @0x0c: Write sample to stimuli FIFO. WARNING: may block.
				tagged AvalonRequest{addr: 3, data: .x, command: Write}:
					stimFifo.enq(truncate(x));
				// Register @0x10: Read/write bin boundary period
				tagged AvalonRequest{addr: 4, data: .x, command: Write}:
					binBoundary.period <= x;
				tagged AvalonRequest{addr: 4, data: .*, command: Read}:
					avalon.busClient.response.put(binBoundary.period);
				// Register @0x14: Read/write word to match
				tagged AvalonRequest{addr: 5, data: .x, command: Write}:
					wordToMatch <= x;
				tagged AvalonRequest{addr: 5, data: .*, command: Read}:
					avalon.busClient.response.put(wordToMatch);
				// Register @0x18: Read/write word valid bits mask
				tagged AvalonRequest{addr: 6, data: .x, command: Write}:
					wordMask <= x;
				tagged AvalonRequest{addr: 6, data: .*, command: Read}:
					avalon.busClient.response.put(wordMask);
				// Register @0x1c: Read/write internal stimuli mem size
				// (size == 0) disables the word finder
				tagged AvalonRequest{addr: 7, data: .x, command: Write}:
					stimMemSize <= truncate(x);
				tagged AvalonRequest{addr: 7, data: .*, command: Read}:
					avalon.busClient.response.put(extend(stimMemSize));
				// Deal with reads to addresses not listed above
				tagged AvalonRequest{addr: .*, data: .*, command: Read}:
					avalon.busClient.response.put(32'hBADC0FFE);
			endcase
		end else begin
			if(cmd.command == Read)
				stimMemPendRead.enq(?);
			stimMem.portB.request.put(BRAMRequest{
				write: cmd.command == Write,
				address: truncate(cmd.addr),
				datain: truncate(cmd.data),
				responseOnWrite: False
			});
		end
	endrule

	(* fire_when_enabled *)
	rule stimLoadFifo(acqStarted && stimRate.ticked);
		(*split*)
		if(stimFifo.notEmpty) begin
			stimOut[0] <= stimFifo.first;
			stimFifo.deq;
		end else begin
			led.errorCondition[1].set;
		end
	endrule

	(* fire_when_enabled *)
	rule stimLoadMem(stimRate.ticked);
        let data <- stimMem.portA.response.get;
		stimOut[1] <= data;//stimFromMem.first;
		stimFromMem.deq;
	endrule

	(*descending_urgency="queryStimMem,jtag_get_addr"*)
	rule jtag_get_addr;
		let stimIndex <- jtag_addr.get;
		stimMem.portA.request.put(BRAMRequest{
			write: False,
			address: stimIndex,
			datain: ?,
			responseOnWrite: False
		});
	endrule

	(*descending_urgency="stimLoadMem,jtag_put_data"*)
	rule jtag_put_data;
		let data <- stimMem.portA.response.get;
		jtag_data.put(data);
	endrule

	(* fire_when_enabled *)
	rule timestampUpdate(acqStarted && cycleCounter.ticked);
		let flags = asReg(channelFlags[0]);
		Bit#(TSub#(NumFlags,1)) truncatedFlags = truncate(flags);
		(*split*)
		if(truncatedFlags != 0) begin
			(*split*)
			if(acqFifo.notFull) begin
				acqFifo.enq(tuple2(flags, timestamp));
			end else begin
				led.errorCondition[0].set;  // TX FIFO overflow
			end
		end
		flags <= 0;
		timestamp <= timestamp + 1;
	endrule

	(* fire_when_enabled, no_implicit_conditions *)
	rule blendChannelFlags(acqStarted);
		channelFlags[1] <= channelFlags[1] | flagIn;
	endrule

	(* fire_when_enabled, no_implicit_conditions *)
	rule wordUpdate(acqStarted && !wordMatched && binBoundary.ticked);
		let b = asReg(wordBit[0]);
		let updword = (word[0] << 1) | extend(b);
		if ((updword & wordMask) == wordToMatch) begin
			if (stimMemSize != 0) begin
				wordMatched <= True;
				stimIndex <= 0;
			end
			updword = 0;
		end
		word[0] <= updword;
		b <= 0;
	endrule

	(* fire_when_enabled, no_implicit_conditions *)
	rule blendWordBit(acqStarted);
		wordBit[1] <= wordBit[1] | flagIn[ chWord ];
	endrule

	(* fire_when_enabled *)
	rule queryStimMem(wordMatched);
		stimMem.portA.request.put(BRAMRequest{
			write: False,
			address: truncate(stimIndex),
			datain: ?,
			responseOnWrite: False
		});
        stimFromMem.enq(truncate(stimIndex));
		wordMatched <= stimIndex + 1 < stimMemSize;
		stimIndex <= stimIndex + 1;
	endrule

	method Stim stimuli = stimOut[0];

	interface irqWires = irqSender(acqFifo.notEmpty);
	interface avalonWires = avalon.slaveWires;
	interface ledWires = led.wires;
	interface inputs = Vector::map(toAcqIn, inSyncs);
endmodule

import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import Connectable::*;
import SysConfig::*;
import AsyncPulseSync::*;
import StatusLED::*;
import CycleCounter::*;
import ProgrammableCycleCounter::*;
import AvalonSlave::*;
import InterruptSender::*;

typedef Tuple2#(Bit#(NumFlags), TimeStamp) AcqFifoContents;

interface AcqSys;
	(* prefix="" *)
	interface InterruptSenderWires irqWires;
	(* prefix="" *)
	interface AvalonSlaveWires#(AvalonAddrSize, AvalonDataSize) avalonWires;
	(* prefix="" *)
	interface StatusLEDWires ledWires;
	(* prefix="CH" *)
	interface Vector#(NumInputs, AcqIn) inputs;
	(* always_ready, prefix="", result="STIM" *)
	method Stim stimuli;
endinterface

(* synthesize, clock_prefix="clk", reset_prefix="reset_n" *)
module mkAcqSys(AcqSys);
	AvalonSlave#(AvalonAddrSize, AvalonDataSize) avalon <- mkAvalonSlave;

	Vector#(NumInputs, SyncPulseIfc) inSyncs <- replicateM(mkAsyncPulseSync);
	Bit#(NumInputs) syncedIn = fromPulseVector(inSyncs);

	Array#(Reg#(Stim)) stimOut <- mkCReg(3, 0);
	CycleCounter#(CyclesStimRate) stimRate <- mkCycleCounter;
	Reg#(Bool) wordMatched <- mkReg(False);
	Bit#(NumFlags) flagIn = {wordMatched?1'b1:1'b0, stimRate.ticked?1'b1:1'b0, syncedIn};

	CycleCounter#(CyclesResolution) cycleCounter <- mkCycleCounter;
	StatusLED#(3) led <- mkStatusLED(flagIn, cycleCounter.ticked);
	Reg#(Bool) acqStarted <- mkReg(False);
	Reg#(TimeStamp) timestamp <- mkReg(0);
	Array#(Reg#(Bit#(NumFlags))) channelFlags <- mkCReg(2, 0);

	FIFOF#(AcqFifoContents) acqFifo <- mkSizedFIFOF(2*valueOf(NumFlags));
	RWire#(AcqFifoContents) acqFifoFirst <- mkRWire;
	FIFOF#(Stim) stimFifo <- mkFIFOF;

	BRAM2Port#(StimMemAddr, Stim) stimMem <- mkBRAM2Server(defaultValue);
	FIFOF#(void) stimMemPendRead <- mkFIFOF;  // to enforce order on responses
	Reg#(Bit#(TAdd#(StimMemAddrSize, 1))) stimMemSize <- mkReg(0);
	Reg#(Bit#(TAdd#(StimMemAddrSize, 1))) stimIndex <- mkReg(0);
	FIFOF#(Stim) stimFromMem <- mkFIFOF;

	ProgrammableCycleCounter#(AvalonDataSize) binBoundary <-
		mkProgrammableCycleCounter(fromInteger(defaultWordPeriod));
	Array#(Reg#(Bit#(1))) wordBit <- mkCReg(2, 0);
	Array#(Reg#(Word)) word <- mkCReg(2, 0);
	Reg#(Word) wordToMatch <- mkReg(32'hFFFFFFFF);
	Reg#(Word) wordMask <- mkReg(0);

	//mkConnection(stimMem.portA.response, toPut(stimFromMem));
    /*(* fire_when_enabled *)
    rule askshjasgsahsahgh;
        let data <- stimMem.portA.response.get;
        stimFromMem.enq(data);
    endrule*/

	(* fire_when_enabled *)
	rule peekAcqFifo;
		acqFifoFirst.wset(acqFifo.first);
	endrule

	(* fire_when_enabled *)
	rule answerStimMemRead;
		let resp <- stimMem.portB.response.get;
		avalon.busClient.response.put(extend(resp));
		stimMemPendRead.deq;
	endrule

	rule handleCmd(!stimMemPendRead.notEmpty);
		let cmd <- avalon.busClient.request.get;
		(*split*)
		if (cmd.addr[stimMemAddrSize] == 1'b0) begin
			(*split*)
			case (cmd) matches
				// Register @0x00: Enable/disable acquisition.
				tagged AvalonRequest{addr: 0, data: .x, command: Write}:
					action
						acqStarted <= x != 0;
						(*split*)
						if(x == 0) begin
							led.errorClear;
							acqFifo.clear;
							stimFifo.clear;
							//word[1] <= 0;
							//stimMemSize <= 0;
							//stimOut[2] <= 0;
						end
					endaction
				tagged AvalonRequest{addr: 0, data: .*, command: Read}:
					avalon.busClient.response.put(acqStarted ? 1 : 0);
				// Register @0x04: Read flags from the FIFO. MSB is zero if data is valid.
				tagged AvalonRequest{addr: 1, data: .*, command: Read}:
					action
						Bit#(NumFlags) flags = tpl_1(fromMaybe(tuple2(0,0), acqFifoFirst.wget));
						Bit#(TSub#(AvalonDataSize, 1)) extFlags = extend(flags);
						Bit#(1) invalidFlag = isValid(acqFifoFirst.wget) ? 0 : 1;
						avalon.busClient.response.put({invalidFlag, extFlags});
					endaction
				// Register @0x08: Read timestamp from the FIFO. WARNING: may block.
				tagged AvalonRequest{addr: 2, data: .*, command: Read}:
					action
						TimeStamp tstamp = tpl_2(acqFifo.first);
						avalon.busClient.response.put(tstamp);
						acqFifo.deq;
					endaction
				// Register @0x0c: Write sample to stimuli FIFO. WARNING: may block.
				tagged AvalonRequest{addr: 3, data: .x, command: Write}:
					stimFifo.enq(truncate(x));
				// Register @0x10: Read/write bin boundary period
				tagged AvalonRequest{addr: 4, data: .x, command: Write}:
					binBoundary.period <= x;
				tagged AvalonRequest{addr: 4, data: .*, command: Read}:
					avalon.busClient.response.put(binBoundary.period);
				// Register @0x14: Read/write word to match
				tagged AvalonRequest{addr: 5, data: .x, command: Write}:
					wordToMatch <= x;
				tagged AvalonRequest{addr: 5, data: .*, command: Read}:
					avalon.busClient.response.put(wordToMatch);
				// Register @0x18: Read/write word valid bits mask
				tagged AvalonRequest{addr: 6, data: .x, command: Write}:
					wordMask <= x;
				tagged AvalonRequest{addr: 6, data: .*, command: Read}:
					avalon.busClient.response.put(wordMask);
				// Register @0x1c: Read/write internal stimuli mem size
				// (size == 0) disables the word finder
				tagged AvalonRequest{addr: 7, data: .x, command: Write}:
					stimMemSize <= truncate(x);
				tagged AvalonRequest{addr: 7, data: .*, command: Read}:
					avalon.busClient.response.put(extend(stimMemSize));
				// Deal with reads to addresses not listed above
				tagged AvalonRequest{addr: .*, data: .*, command: Read}:
					avalon.busClient.response.put(32'hBADC0FFE);
			endcase
		end else begin
			if(cmd.command == Read)
				stimMemPendRead.enq(?);
			stimMem.portB.request.put(BRAMRequest{
				write: cmd.command == Write,
				address: truncate(cmd.addr),
				datain: truncate(cmd.data),
				responseOnWrite: False
			});
		end
	endrule

	(* fire_when_enabled *)
	rule stimLoadFifo(acqStarted && stimRate.ticked);
		(*split*)
		if(stimFifo.notEmpty) begin
			stimOut[0] <= stimFifo.first;
			stimFifo.deq;
		end else begin
			led.errorCondition[1].set;
		end
	endrule

	(* fire_when_enabled *)
	rule stimLoadMem(stimRate.ticked);
        let data <- stimMem.portA.response.get;
		stimOut[1] <= data;//stimFromMem.first;
		stimFromMem.deq;
	endrule

	(* fire_when_enabled *)
	rule timestampUpdate(acqStarted && cycleCounter.ticked);
		let flags = asReg(channelFlags[0]);
		Bit#(TSub#(NumFlags,1)) truncatedFlags = truncate(flags);
		(*split*)
		if(truncatedFlags != 0) begin
			(*split*)
			if(acqFifo.notFull) begin
				acqFifo.enq(tuple2(flags, timestamp));
			end else begin
				led.errorCondition[0].set;  // TX FIFO overflow
			end
		end
		flags <= 0;
		timestamp <= timestamp + 1;
	endrule

	(* fire_when_enabled, no_implicit_conditions *)
	rule blendChannelFlags(acqStarted);
		channelFlags[1] <= channelFlags[1] | flagIn;
	endrule

	(* fire_when_enabled, no_implicit_conditions *)
	rule wordUpdate(acqStarted && !wordMatched && binBoundary.ticked);
		let b = asReg(wordBit[0]);
		let updword = (word[0] << 1) | extend(b);
		if ((updword & wordMask) == wordToMatch) begin
			if (stimMemSize != 0) begin
				wordMatched <= True;
				stimIndex <= 0;
			end
			updword = 0;
		end
		word[0] <= updword;
		b <= 0;
	endrule

	(* fire_when_enabled, no_implicit_conditions *)
	rule blendWordBit(acqStarted);
		wordBit[1] <= wordBit[1] | flagIn[ chWord ];
	endrule

	(* fire_when_enabled *)
	rule queryStimMem(wordMatched);
		stimMem.portA.request.put(BRAMRequest{
			write: False,
			address: truncate(stimIndex),
			datain: ?,
			responseOnWrite: False
		});
        stimFromMem.enq(truncate(stimIndex));
		wordMatched <= stimIndex + 1 < stimMemSize;
		stimIndex <= stimIndex + 1;
	endrule

	method Stim stimuli = stimOut[0];

	interface irqWires = irqSender(acqFifo.notEmpty);
	interface avalonWires = avalon.slaveWires;
	interface ledWires = led.wires;
	interface inputs = Vector::map(toAcqIn, inSyncs);
endmodule