minor cleanup Adapter.bsv

minor cleanup Adapter.bsv

// Copyright (c) 2012 MIT
// Copyright (c) 2012 Nokia, 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 GetPut         ::*;
import FIFOF          ::*;
import SpecialFIFOs   ::*;
import StmtFSM        ::*;
import Assert         ::*;
import Pipe           ::*;

function Bit#(a) rtruncate(Bit#(b) x) provisos(Add#(k,a,b));
   match {.v,.*} = split(x);
   return v;
endfunction

interface AdapterToBus#(numeric type n, type a);
   interface PipeIn#(a) in;
   interface PipeOut#(Bit#(n)) out;
endinterface

interface AdapterFromBus#(numeric type n, type a);
   interface PipeIn#(Bit#(n)) in;
   interface PipeOut#(a) out;
endinterface

module mkAdapterToBus(AdapterToBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1, z, asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max  = fromInteger(valueOf(nwords)) - 1;
   Bit#(paddingsz) padding = 0;

   FIFOF#(Bit#(aszn)) fifo <- mkFIFOF1();
   Reg#(Bit#(32))   count <- mkReg(0);

   let nv = valueOf(n);

   interface PipeIn in;
      method Action enq(a val);
         fifo.enq({padding,pack(val)});
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method Bit#(n) first() if (fifo.notEmpty);
         return rtruncate(fifo.first << (count*fromInteger(nv)));
      endmethod
      method Action deq() if (fifo.notEmpty);
         if (count == max)
            begin
               count <= 0;
               fifo.deq;
            end
         else
            begin
               count <= count + 1;
            end
      endmethod
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

module mkAdapterFromBus(AdapterFromBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1,z,asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max    = fromInteger(valueOf(nwords))-1;

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(32))    count <- mkReg(0);
   FIFOF#(Bit#(asz)) fifo <- mkFIFOF1;

   interface PipeIn in;
      method Action enq(Bit#(n) x) if (count < max || fifo.notFull);
         Bit#(aszn) newbuff = truncate({fbnbuff,x});
         fbnbuff <= newbuff;
         if (count == max)
            begin
               count <= 0;
               fifo.enq(truncate(newbuff));
            end
         else
            begin
               count <= count+1;
            end
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method first = unpack(fifo.first);
      method deq = fifo.deq;
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

interface AdapterIndication;
   method Action done();
endinterface

interface AdapterTb;
   method Action start();
endinterface

module mkAdapterTb#(AdapterIndication indication)(AdapterTb);
   AdapterToBus#(32,Bit#(72)) tb32_72 <- mkAdapterToBus();
   AdapterToBus#(32,Bit#(17)) tb32_17 <- mkAdapterToBus();
   AdapterFromBus#(32,Bit#(72)) fb32_72 <- mkAdapterFromBus();
   AdapterFromBus#(32,Bit#(17)) fb32_17 <- mkAdapterFromBus();

   Reg#(Bit#(10)) timer <- mkReg(0);
   rule timeout;
       timer <= timer+1;
       dynamicAssert(timer < 128, "Timeout");
   endrule

   let fsm <- mkFSM(
      seq
       // test to bit-32
       tb32_72.in.enq(72'h090807060504030201);
       dynamicAssert(tb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!tb32_72.in.notFull, "Adapter full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       $display("tb32_72 word 0 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h00000009, "expecting 00000009");
       tb32_72.out.deq;
       $display("tb32_72 word 1 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h08070605, "expecting 08070605");
       tb32_72.out.deq;
       $display("tb32_72 word 2 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h04030201, "expecting 04030201");
       tb32_72.out.deq;
       dynamicAssert(!tb32_72.out.notEmpty && tb32_72.in.notFull, "Adapter empty and not full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");
       tb32_17.in.enq(17'h10203);
       dynamicAssert(tb32_17.out.notEmpty, "tb32_17 not empty");
       dynamicAssert(!tb32_17.in.notFull, "tb32_17 full");
       $display("tb32_17.out.first %h", tb32_17.out.first);
       dynamicAssert(tb32_17.out.first == (32'h00010203), "Expected 00010203");
       tb32_17.out.deq;
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");

       //test from bit-32
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       fb32_72.in.enq(32'h00000009);
       fb32_72.in.enq(32'h08070605);
       fb32_72.in.enq(32'h04030201);
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;
       fb32_72.in.enq(32'h09080706);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_72.in.enq(32'h05040302);
       fb32_72.in.enq(32'h01000000);
       dynamicAssert(fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_72.in.notFull, "Adapter full");
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h060504030201000000, "Expected 060504030201000000");
       fb32_72.out.deq;
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_17.in.enq(32'h10203);
       dynamicAssert(fb32_17.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_17.in.notFull, "Adapter full");
       $display("fb32_17.out.first %h", fb32_17.out.first);
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;
       dynamicAssert(!fb32_17.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_17.in.notFull, "Adapter not full");

       // they should be duals
       tb32_72.in.enq(72'h090807060504030201);
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;

       tb32_17.in.enq(17'h10203);
       fb32_17.in.enq(tb32_17.out.first);
       tb32_17.out.deq;
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;

       indication.done();
   endseq
   );

   method Action start();
       fsm.start();
   endmethod
endmodule

// Copyright (c) 2012 MIT
// Copyright (c) 2012 Nokia, 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 GetPut         ::*;
import FIFOF          ::*;
import SpecialFIFOs   ::*;
import StmtFSM        ::*;
import Assert         ::*;
import Pipe           ::*;

function Bit#(a) rtruncate(Bit#(b) x) provisos(Add#(k,a,b));
   match {.v,.*} = split(x);
   return v;
endfunction

interface AdapterToBus#(numeric type n, type a);
   interface PipeIn#(a) in;
   interface PipeOut#(Bit#(n)) out;
endinterface

interface AdapterFromBus#(numeric type n, type a);
   interface PipeIn#(Bit#(n)) in;
   interface PipeOut#(a) out;
endinterface

instance ToGet#(AdapterFromBus#(n,a),a);
   function Get#(a) toGet(AdapterFromBus#(n,a) x);
      return (interface Get
		 method ActionValue #(a) get();
		    actionvalue
		       x.out.deq;
		       return x.out.first;
		    endactionvalue
		 endmethod
	      endinterface);
   endfunction
endinstance

instance ToPut#(AdapterToBus#(n,a),a);
   function Put#(a) toPut(AdapterToBus#(n,a) x);
      return (interface Put
		 method Action put(a v);
		    action
		       x.in.enq(v);
		    endaction
		 endmethod
	      endinterface);
   endfunction
endinstance

module mkAdapterToBus(AdapterToBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1, z, asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max  = fromInteger(valueOf(nwords)) - 1;
   Bit#(paddingsz) padding = 0;

   FIFOF#(Bit#(aszn)) fifo <- mkFIFOF1();
   Reg#(Bit#(32))   count <- mkReg(0);

   let nv = valueOf(n);

   interface PipeIn in;
      method Action enq(a val);
         fifo.enq({padding,pack(val)});
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method Bit#(n) first() if (fifo.notEmpty);
         return rtruncate(fifo.first << (count*fromInteger(nv)));
      endmethod
      method Action deq() if (fifo.notEmpty);
         if (count == max)
            begin
               count <= 0;
               fifo.deq;
            end
         else
            begin
               count <= count + 1;
            end
      endmethod
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

module mkAdapterFromBus(AdapterFromBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1,z,asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(32) max    = fromInteger(valueOf(nwords))-1;

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(32))    count <- mkReg(0);
   FIFOF#(Bit#(asz)) fifo <- mkFIFOF1;

   interface PipeIn in;
      method Action enq(Bit#(n) x) if (count < max || fifo.notFull);
         Bit#(aszn) newbuff = truncate({fbnbuff,x});
         fbnbuff <= newbuff;
         if (count == max)
            begin
               count <= 0;
               fifo.enq(truncate(newbuff));
            end
         else
            begin
               count <= count+1;
            end
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method first = unpack(fifo.first);
      method deq = fifo.deq;
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

interface AdapterIndication;
   method Action done();
endinterface
interface AdapterTb;
   method Action start();
endinterface
module mkAdapterTb#(AdapterIndication indication)(AdapterTb);
   AdapterToBus#(32,Bit#(72)) tb32_72 <- mkAdapterToBus();
   AdapterToBus#(32,Bit#(17)) tb32_17 <- mkAdapterToBus();

   AdapterFromBus#(32,Bit#(72)) fb32_72 <- mkAdapterFromBus();
   AdapterFromBus#(32,Bit#(17)) fb32_17 <- mkAdapterFromBus();

   Reg#(Bit#(10)) timer <- mkReg(0);
   rule timeout;
       timer <= timer+1;
       dynamicAssert(timer < 128, "Timeout");
   endrule

   let fsm <- mkFSM(
      seq

       // test to bit-32
       tb32_72.in.enq(72'h090807060504030201);
       dynamicAssert(tb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!tb32_72.in.notFull, "Adapter full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       $display("tb32_72 word 0 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h00000009, "expecting 00000009");
       tb32_72.out.deq;
       $display("tb32_72 word 1 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h08070605, "expecting 08070605");
       tb32_72.out.deq;
       $display("tb32_72 word 2 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h04030201, "expecting 04030201");
       tb32_72.out.deq;
       dynamicAssert(!tb32_72.out.notEmpty && tb32_72.in.notFull, "Adapter empty and not full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");
       tb32_17.in.enq(17'h10203);
       dynamicAssert(tb32_17.out.notEmpty, "tb32_17 not empty");
       dynamicAssert(!tb32_17.in.notFull, "tb32_17 full");
       $display("tb32_17.out.first %h", tb32_17.out.first);
       dynamicAssert(tb32_17.out.first == (32'h00010203), "Expected 00010203");
       tb32_17.out.deq;
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");

       //test from bit-32
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       fb32_72.in.enq(32'h00000009);
       fb32_72.in.enq(32'h08070605);
       fb32_72.in.enq(32'h04030201);
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;
       fb32_72.in.enq(32'h09080706);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_72.in.enq(32'h05040302);
       fb32_72.in.enq(32'h01000000);
       dynamicAssert(fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_72.in.notFull, "Adapter full");
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h060504030201000000, "Expected 060504030201000000");
       fb32_72.out.deq;
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_17.in.enq(32'h10203);
       dynamicAssert(fb32_17.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_17.in.notFull, "Adapter full");
       $display("fb32_17.out.first %h", fb32_17.out.first);
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;
       dynamicAssert(!fb32_17.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_17.in.notFull, "Adapter not full");

       // they should be duals
       tb32_72.in.enq(72'h090807060504030201);
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;

       tb32_17.in.enq(17'h10203);
       fb32_17.in.enq(tb32_17.out.first);
       tb32_17.out.deq;
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;

       indication.done();
   endseq
   );

   method Action start();
       fsm.start();
   endmethod
endmodule


use req.burstLen

use req.burstLen

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

// BSV Libraries
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs :: *;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import BRAMFIFO::*;
import BRAM::*;
import PCIE::*;

// XBSV Libraries
import PcieToAxiBridge::*;
import AxiClientServer::*;
import BRAMFIFOFLevel::*;
import PortalMemory::*;
import PortalRMemory::*;
import Adapter::*;
import SGList::*;

//
// @brief AxiDMA provides the configuration and AXI bus interface for DMA
//
// @param dsz Number of bits in the data bus
// @param dbytes Number of bytes in the data bus
//
interface AxiDMAServer#(numeric type dsz, numeric type dbytes);
   interface DMARequest request;
   interface Axi3Client#(40,dsz,dbytes,12) m_axi;
endinterface

interface ConfigureSglist;
   method Action configuring(Bool c);
   method Action page(Bit#(32) tabsel, Bit#(32) off, Bit#(40) addr);
   method Action readSglist(Bit#(32) pref, Bit#(40) addr);
endinterface

interface AxiDMAWriteInternal#(numeric type dsz, numeric type dbytes);
   interface DMAWrite write;
   interface Axi3WriteClient#(40,dsz,dbytes,12) m_axi_write;
   interface ConfigureSglist configure;
endinterface

interface AxiDMAReadInternal#(numeric type dsz, numeric type dbytes);
   interface DMARead read;
   interface Axi3ReadClient#(40,dsz,12) m_axi_read;
   interface ConfigureSglist configure;
endinterface

typedef enum {Idle, Translate, Address, Data, Done} InternalState deriving(Eq,Bits);

module mkAxiDMAReadInternal#(Integer numRequests, Vector#(numReadClients, DMAReadClient#(dsz)) readClients,
			     DMAIndication dmaIndication)(AxiDMAReadInternal#(dsz,dbytes))
   provisos(Add#(1,a__,dsz),
      Mul#(dbytes,8,dsz));

   SGListMMU sgl <- mkSGListMMU();

   FIFO#(DMAAddressRequest) lreqFifo <- mkPipelineFIFO();
   FIFO#(DMAAddressRequest) reqFifo  <- mkPipelineFIFO();
   FIFO#(DMAAddressRequest) dreqFifo <- mkSizedFIFO(numRequests);
   FIFO#(Bit#(40))        paFifo     <- mkPipelineFIFO();
   FIFO#(DmaChannelId)    chanFifo   <- mkSizedFIFO(numRequests);

   Reg#(DmaChannelId)    selectReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bool)            isConfiguring <- mkReg(False);
   Reg#(Bool)            debugReg <- mkReg(False);

   (* descending_urgency = "loadChannel,incSelectReg" *)
   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numReadClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule sglistEntry if (debugReg);
      let physAddr <- sgl.addrResp();
      dmaIndication.sglistEntry(extend(physAddr));
      debugReg <= False;
   endrule

   rule loadChannel if (valueOf(numReadClients) > 0 && !isConfiguring);
      DMAAddressRequest req = unpack(0);
      if (valueOf(numReadClients) > 0)
	 req <- readClients[selectReg].readReq.get();
      $display("dmaread.loadChannel activeChan=%d handle=%h addr=%h burst=%h", selectReg, req.handle, req.address, req.burstLen);

      lreqFifo.enq(req);
      chanFifo.enq(selectReg);
      sgl.addrReq(truncate(req.handle),req.address);
   endrule

   rule checkSglResp if (!debugReg);
      let physAddr <- sgl.addrResp();
      let req = lreqFifo.first();
      lreqFifo.deq();
      if (physAddr == 0) begin
	 // squash request
	 dmaIndication.badAddr(req.handle, req.address);
      end
      else begin
	 reqFifo.enq(req);
	 paFifo.enq(physAddr);
      end
   endrule

   interface ConfigureSglist configure;
       method Action page(Bit#(32) tabsel, Bit#(32) off, Bit#(40) addr) if (isConfiguring);
	  sgl.page(truncate(tabsel), off, addr);
       endmethod

       method Action readSglist(Bit#(32) pref, Bit#(40) addr) if (!debugReg);
	  debugReg <= True;
	  sgl.addrReq(truncate(pref), addr);
       endmethod
      method Action configuring(Bool c);
	 isConfiguring <= c;
      endmethod
   endinterface

   interface DMARead read;
      method ActionValue#(DmaDbgRec) dbg();
	 return ?;
      endmethod
   endinterface

   interface Axi3ReadClient m_axi_read;
      method ActionValue#(Axi3ReadRequest#(40,12)) address();
	 let req = reqFifo.first();
	 reqFifo.deq();
	 let physAddr = paFifo.first();
	 paFifo.deq();

	 dreqFifo.enq(req);
	 return Axi3ReadRequest{address:physAddr, burstLen:truncate(req.burstLen-1), id:extend(req.tag)};
      endmethod
      method Action data(Axi3ReadResponse#(dsz,12) response);
	 let activeChan = chanFifo.first();
	 let resp = dreqFifo.first();
	 if (valueOf(numReadClients) > 0)
	    readClients[activeChan].readData.put(DMAData { data: response.data, tag: resp.tag});

	 let burstLen = burstReg;
	 if (burstLen == 0)
	    burstLen = resp.burstLen;

	 if (burstLen == 1) begin
	    dreqFifo.deq();
	    chanFifo.deq();
	 end

	 burstReg <= burstLen-1;
      endmethod
   endinterface
endmodule

module mkAxiDMAWriteInternal#(Integer numRequests, Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients,
			      DMAIndication dmaIndication)(AxiDMAWriteInternal#(dsz,dbytes))
   provisos(Add#(1,a__,dsz),
	    Mul#(dbytes,8,dsz),
	    Add#(b__, TAdd#(dsz, 8), 128));
   SGListMMU sgl <- mkSGListMMU();

   FIFO#(DMAAddressRequest) lreqFifo <- mkPipelineFIFO();
   FIFO#(DMAAddressRequest) reqFifo <- mkFIFO();
   FIFO#(DMAAddressRequest) dreqFifo <- mkSizedFIFO(numRequests);
   FIFO#(Bit#(40))        paFifo     <- mkFIFO();
   FIFO#(DmaChannelId)    chanFifo <- mkSizedFIFO(numRequests);
   FIFO#(DmaChannelId)    respFifo <- mkSizedFIFO(numRequests);

   Reg#(DmaChannelId)    selectReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bool)            isConfiguring <- mkReg(False);
   Reg#(Bool)            debugReg <- mkReg(False);

   (* descending_urgency = "loadChannel,incSelectReg" *)
   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numWriteClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule readEntry if (debugReg);
      let physAddr <- sgl.addrResp();
      dmaIndication.sglistEntry(extend(physAddr));
      debugReg <= False;
   endrule

   rule loadChannel if (valueOf(numWriteClients) > 0 && !isConfiguring);
      DMAAddressRequest req = unpack(0);
      if (valueOf(numWriteClients) > 0)
	 req <- writeClients[selectReg].writeReq.get();
      $display("dmawrite.loadChannel activeChan=%d handle=%h addr=%h burst=%h debugReq=%d", selectReg, req.handle, req.address, req.burstLen, debugReg);

      lreqFifo.enq(req);
      chanFifo.enq(selectReg);
      sgl.addrReq(truncate(req.handle),req.address);
   endrule

   rule checkSglResp if (!debugReg);
      let physAddr <- sgl.addrResp();
      let req = lreqFifo.first();
      lreqFifo.deq();
      if (physAddr == 0) begin
	 // squash request
	 $display("dmaWrite: badAddr handle=%d addr=%h physAddr=%h", req.handle, req.address, physAddr);
	 dmaIndication.badAddr(req.handle, req.address);
      end
      else begin
	 reqFifo.enq(req);
	 paFifo.enq(physAddr);
      end
   endrule

   interface ConfigureSglist configure;
      method Action page(Bit#(32) tabsel, Bit#(32) off, Bit#(40) addr) if (isConfiguring);
	 sgl.page(truncate(tabsel), off, addr);
      endmethod

      method Action readSglist(Bit#(32) pref, Bit#(40) addr) if (!debugReg);
	 debugReg <= True;
	 sgl.addrReq(truncate(pref), addr);
      endmethod
      method Action configuring(Bool c);
	 isConfiguring <= c;
      endmethod
   endinterface

   interface DMAWrite write;
      method ActionValue#(DmaDbgRec) dbg();
	 return ?;
      endmethod
   endinterface

   interface Axi3WriteClient m_axi_write;
      method ActionValue#(Axi3WriteRequest#(40,12)) address();
	 let req = reqFifo.first();
	 reqFifo.deq();
	 let physAddr = paFifo.first();
	 paFifo.deq();
	 $display("dmaWrite addr physAddr=%h burstReg=%d", physAddr, req.burstLen);

	 dreqFifo.enq(req);
	 return Axi3WriteRequest{address:physAddr, burstLen:truncate(req.burstLen-1), id:extend(req.tag)};
      endmethod
      method ActionValue#(Axi3WriteData#(dsz, dbytes, 12)) data();
	 let activeChan = chanFifo.first();
	 let resp = dreqFifo.first();
	 DMAData#(dsz) tagdata = unpack(0);
	 if (valueOf(numWriteClients) > 0)
	    tagdata <- writeClients[activeChan].writeData.get();
	 let burstLen = burstReg;
	 if (burstLen == 0)
	    burstLen = resp.burstLen;

	 if (burstLen == 1) begin
	    dreqFifo.deq();
	    chanFifo.deq();
	    respFifo.enq(activeChan);
	 end

	 $display("dmaWrite data data=%h burstLen=%d", tagdata.data, burstLen);

	 burstReg <= burstLen-1;

	 Bit#(1) last = burstLen == 1 ? 1'b1 : 1'b0;

	 return Axi3WriteData { data: tagdata.data, byteEnable: maxBound, last: last, id: extend(tagdata.tag) };
      endmethod
      method Action response(Axi3WriteResponse#(12) resp);
	 let activeChan = respFifo.first();
	 respFifo.deq();
	 if (valueOf(numWriteClients) > 0)
	    writeClients[activeChan].writeDone.put(truncate(resp.id));
      endmethod
   endinterface
endmodule

//
// @brief Creates a DMA controller for DMA read and write clients
//
// @param dmaIndication Interface for notifying software
// @param readClients The read clients.
// @param writeClients The writeclients.
//
module mkAxiDMAServer#(DMAIndication dmaIndication,
		       Integer numRequests,
		       Vector#(numReadClients, DMAReadClient#(dsz)) readClients,
		       Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients)
   (AxiDMAServer#(dsz,dbytes))
   provisos (Add#(1,a__,dsz),
	     Mul#(dbytes,8,dsz),
	     Add#(dsz, b__, 120));

   AxiDMAReadInternal#(dsz,dbytes) reader <- mkAxiDMAReadInternal(numRequests, readClients, dmaIndication);
   AxiDMAWriteInternal#(dsz,dbytes) writer <- mkAxiDMAWriteInternal(numRequests, writeClients, dmaIndication);

   Reg#(Bit#(40)) addrReg         <- mkReg(0);
   Reg#(Bit#(32)) prefReg         <- mkReg(0);
   Reg#(Bit#(32))  lenReg         <- mkReg(0);
   Reg#(Bit#(32))  idxReg         <- mkReg(0);

   let page_shift = fromInteger(valueOf(SGListPageShift));

   rule write_pages(idxReg < lenReg);
      idxReg <= idxReg + 1;
      addrReg <= addrReg + 1;
      writer.configure.page(prefReg,idxReg,addrReg);
      reader.configure.page(prefReg,idxReg,addrReg);
      if(idxReg+1 == lenReg) begin
	 reader.configure.configuring(False);
	 writer.configure.configuring(False);
	 dmaIndication.sglistResp(prefReg, idxReg);
      end
   endrule

   interface DMARequest request;
      method Action getStateDbg(ChannelType rc);
	 let rv = ?;
	 if (rc == Read)
	    rv <- reader.read.dbg;
	 else
	    rv <- writer.write.dbg;
	 dmaIndication.reportStateDbg(rv);
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(40) addr, Bit#(32) len) if (idxReg == lenReg);
	 let idx = idxReg;
	 if (prefReg != pref)
	    idx = 0;
	 prefReg <= pref;
	 lenReg  <= (len >> page_shift) + idx;
	 addrReg <= addr >> page_shift;
	 idxReg <= idx;
	 if (addr == 0 && len == 0) begin // sw marks end-of-list with zeros
	    dmaIndication.sglistResp(pref, idx);
	 end
	 else begin
	    reader.configure.configuring(True);
	    writer.configure.configuring(True);
	 end
      endmethod
      method Action readSglist(ChannelType rc, Bit#(32) handle, Bit#(64) addr);
	 if (rc == Read)
	    reader.configure.readSglist(handle, truncate(addr));
	 else
	    writer.configure.readSglist(handle, truncate(addr));
      endmethod
   endinterface
   interface Axi3Client m_axi;
      interface Axi3WriteClient write = writer.m_axi_write;
      interface Axi3ReadClient read = reader.m_axi_read;
   endinterface
endmodule

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

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

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

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

// BSV Libraries
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs :: *;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import BRAMFIFO::*;
import BRAM::*;
import PCIE::*;

// XBSV Libraries
import PcieToAxiBridge::*;
import AxiClientServer::*;
import BRAMFIFOFLevel::*;
import PortalMemory::*;
import PortalRMemory::*;
import Adapter::*;
import SGList::*;

//
// @brief AxiDMA provides the configuration and AXI bus interface for DMA
//
// @param dsz Number of bits in the data bus
// @param dbytes Number of bytes in the data bus
//
interface AxiDMAServer#(numeric type dsz, numeric type dbytes);
   interface DMARequest request;
   interface Axi3Client#(40,dsz,dbytes,12) m_axi;
endinterface

interface ConfigureSglist;
   method Action configuring(Bool c);
   method Action page(Bit#(32) tabsel, Bit#(32) off, Bit#(40) addr);
   method Action readSglist(Bit#(32) pref, Bit#(40) addr);
endinterface

interface AxiDMAWriteInternal#(numeric type dsz, numeric type dbytes);
   interface DMAWrite write;
   interface Axi3WriteClient#(40,dsz,dbytes,12) m_axi_write;
   interface ConfigureSglist configure;
endinterface

interface AxiDMAReadInternal#(numeric type dsz, numeric type dbytes);
   interface DMARead read;
   interface Axi3ReadClient#(40,dsz,12) m_axi_read;
   interface ConfigureSglist configure;
endinterface

typedef enum {Idle, Translate, Address, Data, Done} InternalState deriving(Eq,Bits);

module mkAxiDMAReadInternal#(Integer numRequests, Vector#(numReadClients, DMAReadClient#(dsz)) readClients,
			     DMAIndication dmaIndication)(AxiDMAReadInternal#(dsz,dbytes))
   provisos(Add#(1,a__,dsz),
      Mul#(dbytes,8,dsz));

   SGListMMU sgl <- mkSGListMMU();

   FIFO#(DMAAddressRequest) lreqFifo <- mkPipelineFIFO();
   FIFO#(DMAAddressRequest) reqFifo  <- mkPipelineFIFO();
   FIFO#(DMAAddressRequest) dreqFifo <- mkSizedFIFO(numRequests);
   FIFO#(Bit#(40))        paFifo     <- mkPipelineFIFO();
   FIFO#(DmaChannelId)    chanFifo   <- mkSizedFIFO(numRequests);

   Reg#(DmaChannelId)    selectReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bool)            isConfiguring <- mkReg(False);
   Reg#(Bool)            debugReg <- mkReg(False);

   (* descending_urgency = "loadChannel,incSelectReg" *)
   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numReadClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule sglistEntry if (debugReg);
      let physAddr <- sgl.addrResp();
      dmaIndication.sglistEntry(extend(physAddr));
      debugReg <= False;
   endrule

   rule loadChannel if (valueOf(numReadClients) > 0 && !isConfiguring);
      DMAAddressRequest req = unpack(0);
      if (valueOf(numReadClients) > 0)
	 req <- readClients[selectReg].readReq.get();
      $display("dmaread.loadChannel activeChan=%d handle=%h addr=%h burst=%h", selectReg, req.handle, req.address, req.burstLen);

      lreqFifo.enq(req);
      chanFifo.enq(selectReg);
      sgl.addrReq(truncate(req.handle),req.address);
   endrule

   rule checkSglResp if (!debugReg);
      let physAddr <- sgl.addrResp();
      let req = lreqFifo.first();
      lreqFifo.deq();
      if (physAddr == 0) begin
	 // squash request
	 dmaIndication.badAddr(req.handle, req.address);
      end
      else begin
	 reqFifo.enq(req);
	 paFifo.enq(physAddr);
      end
   endrule

   interface ConfigureSglist configure;
       method Action page(Bit#(32) tabsel, Bit#(32) off, Bit#(40) addr) if (isConfiguring);
	  sgl.page(truncate(tabsel), off, addr);
       endmethod

       method Action readSglist(Bit#(32) pref, Bit#(40) addr) if (!debugReg);
	  debugReg <= True;
	  sgl.addrReq(truncate(pref), addr);
       endmethod
      method Action configuring(Bool c);
	 isConfiguring <= c;
      endmethod
   endinterface

   interface DMARead read;
      method ActionValue#(DmaDbgRec) dbg();
	 return ?;
      endmethod
   endinterface

   interface Axi3ReadClient m_axi_read;
      method ActionValue#(Axi3ReadRequest#(40,12)) address();
	 let req = reqFifo.first();
	 reqFifo.deq();
	 let physAddr = paFifo.first();
	 paFifo.deq();

	 dreqFifo.enq(req);
	 return Axi3ReadRequest{address:physAddr, burstLen:truncate(req.burstLen-1), id:extend(req.tag)};
      endmethod
      method Action data(Axi3ReadResponse#(dsz,12) response);
	 let activeChan = chanFifo.first();
	 let resp = dreqFifo.first();
	 if (valueOf(numReadClients) > 0)
	    readClients[activeChan].readData.put(DMAData { data: response.data, tag: resp.tag});

	 let burstLen = burstReg;
	 if (burstLen == 0)
	    burstLen = resp.burstLen;

	 if (burstLen == 1) begin
	    dreqFifo.deq();
	    chanFifo.deq();
	 end

	 burstReg <= burstLen-1;
      endmethod
   endinterface
endmodule

module mkAxiDMAWriteInternal#(Integer numRequests, Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients,
			      DMAIndication dmaIndication)(AxiDMAWriteInternal#(dsz,dbytes))
   provisos(Add#(1,a__,dsz),
	    Mul#(dbytes,8,dsz),
	    Add#(b__, TAdd#(dsz, 8), 128));
   SGListMMU sgl <- mkSGListMMU();

   FIFO#(DMAAddressRequest) lreqFifo <- mkPipelineFIFO();
   FIFO#(DMAAddressRequest) reqFifo <- mkFIFO();
   FIFO#(DMAAddressRequest) dreqFifo <- mkSizedFIFO(numRequests);
   FIFO#(Bit#(40))        paFifo     <- mkFIFO();
   FIFO#(DmaChannelId)    chanFifo <- mkSizedFIFO(numRequests);
   FIFO#(DmaChannelId)    respFifo <- mkSizedFIFO(numRequests);

   Reg#(DmaChannelId)    selectReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bool)            isConfiguring <- mkReg(False);
   Reg#(Bool)            debugReg <- mkReg(False);

   (* descending_urgency = "loadChannel,incSelectReg" *)
   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numWriteClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule readEntry if (debugReg);
      let physAddr <- sgl.addrResp();
      dmaIndication.sglistEntry(extend(physAddr));
      debugReg <= False;
   endrule

   rule loadChannel if (valueOf(numWriteClients) > 0 && !isConfiguring);
      DMAAddressRequest req = unpack(0);
      if (valueOf(numWriteClients) > 0)
	 req <- writeClients[selectReg].writeReq.get();
      $display("dmawrite.loadChannel activeChan=%d handle=%h addr=%h burst=%h debugReq=%d", selectReg, req.handle, req.address, req.burstLen, debugReg);

      lreqFifo.enq(req);
      chanFifo.enq(selectReg);
      sgl.addrReq(truncate(req.handle),req.address);
   endrule

   rule checkSglResp if (!debugReg);
      let physAddr <- sgl.addrResp();
      let req = lreqFifo.first();
      lreqFifo.deq();
      if (physAddr == 0) begin
	 // squash request
	 $display("dmaWrite: badAddr handle=%d addr=%h physAddr=%h", req.handle, req.address, physAddr);
	 dmaIndication.badAddr(req.handle, req.address);
      end
      else begin
	 reqFifo.enq(req);
	 paFifo.enq(physAddr);
      end
   endrule

   interface ConfigureSglist configure;
      method Action page(Bit#(32) tabsel, Bit#(32) off, Bit#(40) addr) if (isConfiguring);
	 sgl.page(truncate(tabsel), off, addr);
      endmethod

      method Action readSglist(Bit#(32) pref, Bit#(40) addr) if (!debugReg);
	 debugReg <= True;
	 sgl.addrReq(truncate(pref), addr);
      endmethod
      method Action configuring(Bool c);
	 isConfiguring <= c;
      endmethod
   endinterface

   interface DMAWrite write;
      method ActionValue#(DmaDbgRec) dbg();
	 return ?;
      endmethod
   endinterface

   interface Axi3WriteClient m_axi_write;
      method ActionValue#(Axi3WriteRequest#(40,12)) address();
	 let req = reqFifo.first();
	 reqFifo.deq();
	 let physAddr = paFifo.first();
	 paFifo.deq();
	 $display("dmaWrite addr physAddr=%h", physAddr);

	 dreqFifo.enq(req);
	 return Axi3WriteRequest{address:physAddr, burstLen:truncate(burstReg-1), id:extend(req.tag)};
      endmethod
      method ActionValue#(Axi3WriteData#(dsz, dbytes, 12)) data();
	 let activeChan = chanFifo.first();
	 let resp = dreqFifo.first();
	 DMAData#(dsz) tagdata = unpack(0);
	 if (valueOf(numWriteClients) > 0)
	    tagdata <- writeClients[activeChan].writeData.get();
	 let burstLen = burstReg;
	 if (burstLen == 0)
	    burstLen = resp.burstLen;

	 if (burstLen == 1) begin
	    dreqFifo.deq();
	    chanFifo.deq();
	    respFifo.enq(activeChan);
	 end

	 $display("dmaWrite data data=%h", tagdata.data);

	 burstReg <= burstLen-1;

	 Bit#(1) last = burstLen == 1 ? 1'b1 : 1'b0;

	 return Axi3WriteData { data: tagdata.data, byteEnable: maxBound, last: last, id: extend(tagdata.tag) };
      endmethod
      method Action response(Axi3WriteResponse#(12) resp);
	 let activeChan = respFifo.first();
	 respFifo.deq();
	 if (valueOf(numWriteClients) > 0)
	    writeClients[activeChan].writeDone.put(truncate(resp.id));
      endmethod
   endinterface
endmodule

//
// @brief Creates a DMA controller for DMA read and write clients
//
// @param dmaIndication Interface for notifying software
// @param readClients The read clients.
// @param writeClients The writeclients.
//
module mkAxiDMAServer#(DMAIndication dmaIndication,
		       Integer numRequests,
		       Vector#(numReadClients, DMAReadClient#(dsz)) readClients,
		       Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients)
   (AxiDMAServer#(dsz,dbytes))
   provisos (Add#(1,a__,dsz),
	     Mul#(dbytes,8,dsz),
	     Add#(dsz, b__, 120));

   AxiDMAReadInternal#(dsz,dbytes) reader <- mkAxiDMAReadInternal(numRequests, readClients, dmaIndication);
   AxiDMAWriteInternal#(dsz,dbytes) writer <- mkAxiDMAWriteInternal(numRequests, writeClients, dmaIndication);

   Reg#(Bit#(40)) addrReg         <- mkReg(0);
   Reg#(Bit#(32)) prefReg         <- mkReg(0);
   Reg#(Bit#(32))  lenReg         <- mkReg(0);
   Reg#(Bit#(32))  idxReg         <- mkReg(0);

   let page_shift = fromInteger(valueOf(SGListPageShift));

   rule write_pages(idxReg < lenReg);
      idxReg <= idxReg + 1;
      addrReg <= addrReg + 1;
      writer.configure.page(prefReg,idxReg,addrReg);
      reader.configure.page(prefReg,idxReg,addrReg);
      if(idxReg+1 == lenReg) begin
	 reader.configure.configuring(False);
	 writer.configure.configuring(False);
	 dmaIndication.sglistResp(prefReg, idxReg);
      end
   endrule

   interface DMARequest request;
      method Action getStateDbg(ChannelType rc);
	 let rv = ?;
	 if (rc == Read)
	    rv <- reader.read.dbg;
	 else
	    rv <- writer.write.dbg;
	 dmaIndication.reportStateDbg(rv);
      endmethod
      method Action sglist(Bit#(32) pref, Bit#(40) addr, Bit#(32) len) if (idxReg == lenReg);
	 let idx = idxReg;
	 if (prefReg != pref)
	    idx = 0;
	 prefReg <= pref;
	 lenReg  <= (len >> page_shift) + idx;
	 addrReg <= addr >> page_shift;
	 idxReg <= idx;
	 if (addr == 0 && len == 0) begin // sw marks end-of-list with zeros
	    dmaIndication.sglistResp(pref, idx);
	 end
	 else begin
	    reader.configure.configuring(True);
	    writer.configure.configuring(True);
	 end
      endmethod
      method Action readSglist(ChannelType rc, Bit#(32) handle, Bit#(64) addr);
	 if (rc == Read)
	    reader.configure.readSglist(handle, truncate(addr));
	 else
	    writer.configure.readSglist(handle, truncate(addr));
      endmethod
   endinterface
   interface Axi3Client m_axi;
      interface Axi3WriteClient write = writer.m_axi_write;
      interface Axi3ReadClient read = reader.m_axi_read;
   endinterface
endmodule