change to 14 bits for longer strings

change to 14 bits for longer strings

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

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

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

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

import StmtFSM::*;
import BRAM::*;
import MCSAlgorithm::*;

module mkHirschB#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL, int dir)(MCSAlgorithm)
         provisos(Add#(0, 14, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(14)) aStartReg <- mkReg(0);
   Reg#(Bit#(14)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(14)) aLenReg <- mkReg(0);
   Reg#(Bit#(14)) bLenReg <- mkReg(0);
   Reg#(Bit#(14)) ii <- mkReg(0);
   Reg#(Bit#(14)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) k1j <- mkReg(0);
   Reg#(Bit#(16)) k1jm1 <- mkReg(0);
   Reg#(Bit#(16)) k0j <- mkReg(0);
   Reg#(Bit#(16)) k0jm1 <- mkReg(0);
   BRAM1Port#(Bit#(lIndexWidth), Bit#(16)) k0  <- mkBRAM1Server(defaultValue);

/* The original algorithm B uses two vectors K0 and K1 to store two rows of the full L
 * matrix from algoritm A.  For any particular iteration, K[0][j-1] K[0][j]
 * and K[1][j-1] are used to compute K[1][j]
 *
 * Each cycle, K[1] is copied to K[0], and then a new K[1] is computed.  First, the
 * the previous K[0][j] is copied to K[0][j-1] and the previous K[1][j] is copied to
 * K[1][j-1].  Then a new K[1][j] is computed.
 *
 * In the revised version, a single vector is used, plus auxiliary registers.
 * First the old K[0][j] auxiliary is copied to K[0][j-1] and the K[1][j] auxiliary
 * is copied to K[1][j-1].  Then K[0][j] is read. Then K[1][j] is computed <and written> to
 * K[0][j].  When the row is finished, K[0] is effectively K[1]
 *
 */

  Stmt hirschB =
   seq
      jj <= 17;  // one cycle delay to permit the control registers to get set
      //$display("hirschB running %d %d %d %d dir %d",
	// aStartReg, aLenReg, bStartReg, bLenReg, dir);
      /* initialize K1 (stored in lMat) of temporary storage */
      for (jj <= 0; jj <= bLenReg; jj <= jj + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: 0});
	 endseq
      /* Loop through string a */
      for (ii <= 1; ii <= aLenReg; ii <= ii + 1)
	 seq
	    //$display("hirschB ii = %d", ii);
	    par
	       /* initialize pipelining */
	       jj <= 1;
	       k0j <= 0;
	       k1j <= 0;
	       action
		  let idx = ?;
		  if (dir == 1)
		     idx = aStartReg + ii - 1;  // 0 to aLen - 1
		  else
		     idx = aStartReg + aLenReg - ii;  // aLen-1 downto 0
		  strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: idx, datain: 0});
	       endaction
	       /* Read b[j] */
	       action
		  let idx = ?;
		  if (dir == 1)
		     idx = bStartReg;
		  else
		     idx = bStartReg + bLenReg - 1;
		  strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: idx, datain: 0});
	       endaction
	       /* start read of k0j */
	       matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: rStartReg + 1, datain: 0});
	    endpar
	    action
	       let ta <- strA.response.get(); /* read a[i] */
	       aData <= ta;
	    endaction

	    /* Loop through string B */
	    while (jj <= bLenReg)
	       seq
		  //$display("hirschB jj = %d", jj);
		  action
		     let tb <- strB.response.get();
		     let tk <- matL.response.get();
		     k0jm1 <= k0j;  /* pipeline from previous cycle */
		     k1jm1 <= k1j;
		     bData <= tb;   /* read b[j] from bram */
		     k0j <= tk;     /* read k[0][j] from bram */
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
		  endaction
		  //$display("hirschB ii %d jj %d A %h B %h k1j", ii, jj, aData, bData, k1j);
		  action
		     let tmp = ?;
		     /* Read b[j] */
		     /* if backwards B[bStartReg + bLenReg - jj] */
		     action
			let idx = ?;
			if (dir == 1)
			   idx = bStartReg + jj;
			else
			   idx = bStartReg + bLenReg - jj - 1;
			strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: idx, datain: 0});
		     endaction
		     if (aData == bData)
			tmp = k0jm1 + 1;
		     else
		        tmp = max(k0j,k1jm1);
		     k1j <= tmp;
		     jj <= jj + 1;
		     /* start read of k0j */
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: rStartReg + zeroExtend(jj+1), datain: 0});
		  endaction
		  //$display("     L[%d][%d] = %d ", ii, jj, k1j);
	       endseq
	    action
	       let tb <- strB.response.get();
	       let tk <- matL.response.get();
	       matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
	    endaction
	 endseq
   endseq;

   FSM hB <- mkFSM(hirschB);

   method Action setupA(Bit#(14) start, Bit#(14) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(14) start, Bit#(14) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
      rStartReg <= start;
   endmethod

   method Bit#(14) result();
      return(zeroExtend(bLenReg));
   endmethod

   interface FSM fsm = hB;

endmodule

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

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

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

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

import StmtFSM::*;
import BRAM::*;
import MCSAlgorithm::*;

module mkHirschB#(BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA, BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB, BRAMServer#(Bit#(lIndexWidth), Bit#(16)) matL, int dir)(MCSAlgorithm)
         provisos(Add#(0, 7, strIndexWidth),
	       Add#(0, 14, lIndexWidth));

   Reg#(Bit#(7)) aStartReg <- mkReg(0);
   Reg#(Bit#(7)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(7)) aLenReg <- mkReg(0);
   Reg#(Bit#(7)) bLenReg <- mkReg(0);
   Reg#(Bit#(7)) ii <- mkReg(0);
   Reg#(Bit#(7)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(16)) k1j <- mkReg(0);
   Reg#(Bit#(16)) k1jm1 <- mkReg(0);
   Reg#(Bit#(16)) k0j <- mkReg(0);
   Reg#(Bit#(16)) k0jm1 <- mkReg(0);
   BRAM1Port#(Bit#(lIndexWidth), Bit#(16)) k0  <- mkBRAM1Server(defaultValue);

/* The original algorithm B uses two vectors K0 and K1 to store two rows of the full L
 * matrix from algoritm A.  For any particular iteration, K[0][j-1] K[0][j]
 * and K[1][j-1] are used to compute K[1][j]
 *
 * Each cycle, K[1] is copied to K[0], and then a new K[1] is computed.  First, the
 * the previous K[0][j] is copied to K[0][j-1] and the previous K[1][j] is copied to
 * K[1][j-1].  Then a new K[1][j] is computed.
 *
 * In the revised version, a single vector is used, plus auxiliary registers.
 * First the old K[0][j] auxiliary is copied to K[0][j-1] and the K[1][j] auxiliary
 * is copied to K[1][j-1].  Then K[0][j] is read. Then K[1][j] is computed <and written> to
 * K[0][j].  When the row is finished, K[0] is effectively K[1]
 *
 */

  Stmt hirschB =
   seq
      jj <= 17;  // one cycle delay to permit the control registers to get set
      //$display("hirschB running %d %d %d %d dir %d",
	// aStartReg, aLenReg, bStartReg, bLenReg, dir);
      /* initialize K1 (stored in lMat) of temporary storage */
      for (jj <= 0; jj <= bLenReg; jj <= jj + 1)
	 seq
	    matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj), datain: 0});
	 endseq
      /* Loop through string a */
      for (ii <= 1; ii <= aLenReg; ii <= ii + 1)
	 seq
	    //$display("hirschB ii = %d", ii);
	    par
	       /* initialize pipelining */
	       jj <= 1;
	       k0j <= 0;
	       k1j <= 0;
	       action
		  let idx = ?;
		  if (dir == 1)
		     idx = aStartReg + ii - 1;  // 0 to aLen - 1
		  else
		     idx = aStartReg + aLenReg - ii;  // aLen-1 downto 0
		  strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: idx, datain: 0});
	       endaction
	       /* Read b[j] */
	       action
		  let idx = ?;
		  if (dir == 1)
		     idx = bStartReg;
		  else
		     idx = bStartReg + bLenReg - 1;
		  strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: idx, datain: 0});
	       endaction
	       /* start read of k0j */
	       matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: rStartReg + 1, datain: 0});
	    endpar
	    action
	       let ta <- strA.response.get(); /* read a[i] */
	       aData <= ta;
	    endaction

	    /* Loop through string B */
	    while (jj <= bLenReg)
	       seq
		  //$display("hirschB jj = %d", jj);
		  action
		     let tb <- strB.response.get();
		     let tk <- matL.response.get();
		     k0jm1 <= k0j;  /* pipeline from previous cycle */
		     k1jm1 <= k1j;
		     bData <= tb;   /* read b[j] from bram */
		     k0j <= tk;     /* read k[0][j] from bram */
		     matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
		  endaction
		  //$display("hirschB ii %d jj %d A %h B %h k1j", ii, jj, aData, bData, k1j);
		  action
		     let tmp = ?;
		     /* Read b[j] */
		     /* if backwards B[bStartReg + bLenReg - jj] */
		     action
			let idx = ?;
			if (dir == 1)
			   idx = bStartReg + jj;
			else
			   idx = bStartReg + bLenReg - jj - 1;
			strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: idx, datain: 0});
		     endaction
		     if (aData == bData)
			tmp = k0jm1 + 1;
		     else
		        tmp = max(k0j,k1jm1);
		     k1j <= tmp;
		     jj <= jj + 1;
		     /* start read of k0j */
		     matL.request.put(BRAMRequest{write: False, responseOnWrite: False, address: rStartReg + zeroExtend(jj+1), datain: 0});
		  endaction
		  //$display("     L[%d][%d] = %d ", ii, jj, k1j);
	       endseq
	    action
	       let tb <- strB.response.get();
	       let tk <- matL.response.get();
	       matL.request.put(BRAMRequest{write: True, responseOnWrite: False, address: rStartReg + zeroExtend(jj-1), datain: k1j});
	    endaction
	 endseq
   endseq;

   FSM hB <- mkFSM(hirschB);

   method Action setupA(Bit#(7) start, Bit#(7) length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(7) start, Bit#(7) length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Action setupL(Bit#(14) start);
      rStartReg <= start;
   endmethod

   method Bit#(14) result();
      return(zeroExtend(bLenReg));
   endmethod

   interface FSM fsm = hB;

endmodule


simplify

simplify

// Copyright (c) 2013 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 Vector::*;
import Clocks::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;

import YUV::*;
import NrccSyncBRAM::*;

interface HDMI;
    method Bit#(1) hdmi_vsync;
    method Bit#(1) hdmi_hsync;
    method Bit#(1) hdmi_de;
    method Bit#(16) hdmi_data;
    interface Clock hdmi_clock_if;
    interface Reset hdmi_reset_if;
endinterface

interface HdmiOut;
    method Action rgb(Rgb888VideoData videoData);
    interface HDMI hdmi;
endinterface

interface HdmiGenerator;
    method Action setTestPattern(Bool v);
    method Action setPatternColor(Bit#(32) v);
    method Action setHsyncWidth(Bit#(12) hsyncWidth);
    method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max);
    method Action setVsyncWidth(Bit#(11) vsyncWidth);
    method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max);
    method Action setNumberOfLines(Bit#(11) lines);
    method Action setNumberOfPixels(Bit#(12) pixels);
    interface HDMI hdmi;
endinterface

typedef struct {
    Bit#(11) line;
    Bit#(12) pixel;
} LinePixelCount;

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Rgb888 pixel;
} Rgb888Stage deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Yuv444Intermediates data;
} Yuv444IntermediatesStage deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Yuv444 data;
} Yuv444Stage deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Bit#(16) data;
} Yuv422Stage deriving (Bits);

module mkHdmiGenerator#(Clock axi_clock, Reset axi_reset,
        BRAM#(Bit#(12), Bit#(32)) lineBuffer,
        SyncPulseIfc vsyncPulse, SyncPulseIfc hsyncPulse)(HdmiGenerator);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    // 1920 * 1080
    Reg#(Bit#(12)) hsyncWidth <- mkSyncReg(44, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) dePixelCountMinimum <- mkSyncReg(192, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) dePixelCountMaximum <- mkSyncReg(1920 + 192, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) pixelMidpoint <- mkSyncReg((1920/2) + 192, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) vsyncWidth <- mkSyncReg(5, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) deLineCountMinimum <- mkSyncReg(41, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) deLineCountMaximum <- mkSyncReg(1080+41, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) lineMidpoint <- mkSyncReg((1080/2) + 41, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) numberOfLines <- mkSyncReg(1080 + 45, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) numberOfPixels <- mkSyncReg(1920 + 192 + 44 + 44, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) lineCount <- mkReg(0);
    Reg#(Bit#(12)) pixelCount <- mkReg(0);
    FIFOF#(Rgb888Stage) bramOutStageFifo <- mkSizedFIFOF(8);
    Reg#(Bit#(12)) dataCount <- mkReg(0);
    Reg#(Bit#(32)) patternReg0 <- mkSyncReg(32'h00FFFFFF, axi_clock, axi_reset, defaultClock); // white
    Vector#(4, Reg#(Bit#(32))) patternRegs <- replicateM(mkReg(0));
    Reg#(Bool) shadowTestPatternEnabled <- mkSyncReg(True, axi_clock, axi_reset, defaultClock);
    Reg#(Bool) testPatternEnabled <- mkReg(True);
    HdmiOut hdmioutput <- mkHdmiOut();

    let vsync = (lineCount < vsyncWidth) ? 1 : 0;
    let hsync = (pixelCount < hsyncWidth) ? 1 : 0;
    let isActiveLine = (lineCount >= deLineCountMinimum && lineCount < deLineCountMaximum);
    let dataEnable = (pixelCount >= dePixelCountMinimum && pixelCount < dePixelCountMaximum && isActiveLine);

    // vsyncPulse is a SyncHandshake to a slow clock domain
    // so it is not ready every cycle.
    // Therefore, we send to it from a different rule so it does not block the fbRule
    rule sendVsyncPulse (lineCount == 0 && pixelCount == 0);
        $display("vsync pulse sent");
        vsyncPulse.send();
    endrule

    rule sendHsyncPulse (isActiveLine && pixelCount == 0);
        //$display("hsync pulse sent");
        hsyncPulse.send();
    endrule

    rule init_pattern;
        patternRegs[0] <= patternReg0;
        patternRegs[1] <= 32'h00FF0000; // blue
        patternRegs[2] <= 32'h0000FF00; // green
        patternRegs[3] <= 32'h000000FF; // red
        //patternRegs[1] <= 32'h80ff80ff; // yuv422 white
        //patternRegs[2] <= 32'h2c961596; // yuv422 green
        //patternRegs[3] <= 32'hff1d6b1d; // yuv422 red
        if (lineCount == 0 && pixelCount == 0)
            begin
            $display("testPatternEnabled %d", shadowTestPatternEnabled);
            testPatternEnabled <= shadowTestPatternEnabled;
            end
        if (pixelCount == numberOfPixels-1)
           begin
           pixelCount <= 0;
           if (lineCount == numberOfLines-1)
               lineCount <= 0;
           else
               lineCount <= lineCount+1;
           end
        else
            pixelCount <= pixelCount + 1;
    endrule

    rule data if (testPatternEnabled);
        Bit#(2) index = {pack(lineCount >= lineMidpoint), pack(pixelCount >= pixelMidpoint)};
        bramOutStageFifo.enq(Rgb888Stage { vsync: vsync, hsync: hsync, de: dataEnable,
            pixel: unpack(truncate(patternRegs[index]))});
        lineBuffer.readAddr(0);
    endrule

    rule fbRule if (!testPatternEnabled);
        if (hsync == 1)
            dataCount <= 0;
        else if (dataEnable)
            dataCount <= dataCount + 1;
        bramOutStageFifo.enq(Rgb888Stage { vsync: vsync, hsync: hsync, de: dataEnable,
            pixel: Rgb888{r:0,g:0,b:0}});
        lineBuffer.readAddr(dataCount);
    endrule

    rule bramOutStage;
        bramOutStageFifo.deq();
        let d <- lineBuffer.readData();
        let stageData = bramOutStageFifo.first;

        if (!testPatternEnabled)
            stageData.pixel = unpack(d[23:0]);
        hdmioutput.rgb(Rgb888VideoData{active_video: pack(stageData.de),
            vsync: stageData.vsync, hsync: stageData.hsync,
            r: stageData.pixel.r, g: stageData.pixel.g, b: stageData.pixel.b });
    endrule

    interface hdmi = hdmioutput.hdmi;
    method Action setPatternColor(Bit#(32) v);
        patternReg0 <= v;
    endmethod
    method Action setTestPattern(Bool v);
        shadowTestPatternEnabled <= v;
    endmethod
    method Action setHsyncWidth(Bit#(12) width);
        hsyncWidth <= width;
    endmethod
    method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max);
        dePixelCountMinimum <= min;
        dePixelCountMaximum <= max;
        pixelMidpoint <= (min + max) / 2;
    endmethod
    method Action setVsyncWidth(Bit#(11) width);
        vsyncWidth <= width;
    endmethod
    method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max);
        deLineCountMinimum <= min;
        deLineCountMaximum <= max;
        lineMidpoint <= (min + max) / 2;
    endmethod
    method Action setNumberOfLines(Bit#(11) lines);
        numberOfLines <= lines;
    endmethod
    method Action setNumberOfPixels(Bit#(12) pixels);
        numberOfPixels <= pixels;
    endmethod
endmodule

module mkHdmiOut(HdmiOut);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Reg#(Rgb888Stage) rgb888StageReg <- mkReg(unpack(0));
    Reg#(Yuv444IntermediatesStage) yuv444IntermediatesStageReg <- mkReg(
        Yuv444IntermediatesStage { vsync: 0, hsync: 0, de: False, data: unpack(0) });
    Reg#(Yuv444Stage) yuv444StageReg <- mkReg(
        Yuv444Stage { vsync: 0, hsync: 0, de: False, data: unpack(0) });
    Reg#(Yuv422Stage) yuv422StageReg <- mkReg(
        Yuv422Stage { vsync: 0, hsync: 0, de: False, data: unpack(0) });
    Reg#(Bool) evenOddPixelReg <- mkReg(False);

    rule yuv444IntermediatesStage;
        let previous = rgb888StageReg;
        let pixel = previous.pixel;
        yuv444IntermediatesStageReg <= Yuv444IntermediatesStage {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
            data: (previous.de) ? rgbToYuvIntermediates(pixel) : unpack(0)
        };
    endrule

    rule yuv444Stage;
        let previous = yuv444IntermediatesStageReg;
        yuv444StageReg <= Yuv444Stage {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
            data: (previous.de) ? yuvIntermediatesToYuv444(previous.data) : unpack(0)
        };
    endrule

    rule yuv422stage;
        let previous = yuv444StageReg;
        if (previous.de)
            evenOddPixelReg <= !evenOddPixelReg;
        Bit#(16) data = { evenOddPixelReg ? previous.data.u : previous.data.v,
                          previous.data.y };
        yuv422StageReg <= Yuv422Stage {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
            data: data
        };
    endrule

    method Action rgb(Rgb888VideoData videoData);
        rgb888StageReg <= Rgb888Stage {
            vsync: videoData.vsync, hsync: videoData.hsync,
            de: videoData.active_video == 1 ? True : False,
            pixel: Rgb888 { r: videoData.r, g: videoData.g, b: videoData.b}};
    endmethod
    interface HDMI hdmi;
        method Bit#(1) hdmi_vsync;
            return yuv422StageReg.vsync;
        endmethod
        method Bit#(1) hdmi_hsync;
            return yuv422StageReg.hsync;
        endmethod
        method Bit#(1) hdmi_de;
            return yuv422StageReg.de ? 1 : 0;
        endmethod
        method Bit#(16) hdmi_data;
            return yuv422StageReg.data;
        endmethod
        interface hdmi_clock_if = defaultClock;
        interface hdmi_reset_if = defaultReset;
    endinterface
endmodule

// Copyright (c) 2013 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 Vector::*;
import Clocks::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;

import YUV::*;
import NrccSyncBRAM::*;

interface HDMI;
    method Bit#(1) hdmi_vsync;
    method Bit#(1) hdmi_hsync;
    method Bit#(1) hdmi_de;
    method Bit#(16) hdmi_data;
    interface Clock hdmi_clock_if;
    interface Reset hdmi_reset_if;
endinterface

interface HdmiOut;
    method Action rgb(Rgb888VideoData videoData);
    interface HDMI hdmi;
endinterface

interface HdmiGenerator;
    method Action setTestPattern(Bool v);
    method Action setPatternColor(Bit#(32) v);
    method Action setHsyncWidth(Bit#(12) hsyncWidth);
    method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max);
    method Action setVsyncWidth(Bit#(11) vsyncWidth);
    method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max);
    method Action setNumberOfLines(Bit#(11) lines);
    method Action setNumberOfPixels(Bit#(12) pixels);
    interface HDMI hdmi;
endinterface

typedef struct {
    Bit#(11) line;
    Bit#(12) pixel;
} LinePixelCount;

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Rgb888 pixel;
} Rgb888Stage deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Yuv444Intermediates data;
} Yuv444IntermediatesStage deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Yuv444 data;
} Yuv444Stage deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bool de;
    Bit#(16) data;
} Yuv422Stage deriving (Bits);

module mkHdmiGenerator#(Clock axi_clock, Reset axi_reset,
        BRAM#(Bit#(12), Bit#(32)) lineBuffer,
        SyncPulseIfc vsyncPulse, SyncPulseIfc hsyncPulse)(HdmiGenerator);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    // 1920 * 1080
    Reg#(Bit#(12)) hsyncWidth <- mkSyncReg(44, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) dePixelCountMinimum <- mkSyncReg(192, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) dePixelCountMaximum <- mkSyncReg(1920 + 192, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) pixelMidpoint <- mkSyncReg((1920/2) + 192, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) vsyncWidth <- mkSyncReg(5, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) deLineCountMinimum <- mkSyncReg(41, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) deLineCountMaximum <- mkSyncReg(1080+41, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) lineMidpoint <- mkSyncReg((1080/2) + 41, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) numberOfLines <- mkSyncReg(1080 + 45, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(12)) numberOfPixels <- mkSyncReg(1920 + 192 + 44 + 44, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(11)) lineCount <- mkReg(0);
    Reg#(Bit#(12)) pixelCount <- mkReg(0);
    FIFOF#(Rgb888Stage) bramOutStageFifo <- mkSizedFIFOF(8);
    Reg#(Bit#(12)) dataCount <- mkReg(0);
    Reg#(Bit#(32)) patternReg0 <- mkSyncReg(32'h00FFFFFF, axi_clock, axi_reset, defaultClock); // white
    Vector#(4, Reg#(Bit#(32))) patternRegs <- replicateM(mkReg(0));
    Reg#(Bool) shadowTestPatternEnabled <- mkSyncReg(True, axi_clock, axi_reset, defaultClock);
    Reg#(Bool) testPatternEnabled <- mkReg(True);
    HdmiOut hdmioutput <- mkHdmiOut();

    let vsync = (lineCount < vsyncWidth) ? 1 : 0;
    let hsync = (pixelCount < hsyncWidth) ? 1 : 0;
    let isActiveLine = (lineCount >= deLineCountMinimum && lineCount < deLineCountMaximum);
    let dataEnable = (pixelCount >= dePixelCountMinimum && pixelCount < dePixelCountMaximum && isActiveLine);

    function LinePixelCount newCounts(Bit#(11) lc, Bit#(12) pc);
        let newLineCount = lc;
        let newPixelCount = pc;
        if (pc == numberOfPixels-1)
           begin
           newPixelCount = 0;
           if (lc == numberOfLines-1)
               newLineCount = 0;
           else
               newLineCount = lc+1;
           end
        else
            newPixelCount = pc + 1;
        return LinePixelCount { line: newLineCount, pixel: newPixelCount };
    endfunction

    // vsyncPulse is a SyncHandshake to a slow clock domain
    // so it is not ready every cycle.
    // Therefore, we send to it from a different rule so it does not block the fbRule
    rule sendVsyncPulse (lineCount == 0 && pixelCount == 0);
        $display("vsync pulse sent");
        vsyncPulse.send();
    endrule

    rule sendHsyncPulse (isActiveLine && pixelCount == 0);
        //$display("hsync pulse sent");
        hsyncPulse.send();
    endrule

    rule init_pattern;
        patternRegs[0] <= patternReg0;
        patternRegs[1] <= 32'h00FF0000; // blue
        patternRegs[2] <= 32'h0000FF00; // green
        patternRegs[3] <= 32'h000000FF; // red
        //patternRegs[1] <= 32'h80ff80ff; // yuv422 white
        //patternRegs[2] <= 32'h2c961596; // yuv422 green
        //patternRegs[3] <= 32'hff1d6b1d; // yuv422 red
    endrule

    rule data if (testPatternEnabled);
        LinePixelCount counts = newCounts(lineCount, pixelCount);
        lineCount <= counts.line;
        pixelCount <= counts.pixel;
        if (lineCount == 0 && pixelCount == 0)
        begin
            $display("testPatternEnabled %d", shadowTestPatternEnabled);
            testPatternEnabled <= shadowTestPatternEnabled;
        end

        Bit#(2) index = {pack(lineCount >= lineMidpoint), pack(pixelCount >= pixelMidpoint)};
        //if (pixelCount >= pixelMidpoint)
            //index[0] = 1;
        //if (lineCount >= lineMidpoint)
            //index[1] = 1;
        //Bit#(32) data = patternRegs[index];

        if (hsync == 1)
            dataCount <= 0;
        else if (dataEnable)
            dataCount <= dataCount + 1;
        bramOutStageFifo.enq(Rgb888Stage { vsync: vsync, hsync: hsync, de: dataEnable, pixel: unpack(truncate(patternRegs[index]))});
        lineBuffer.readAddr(0);
    endrule

    rule fbRule if (!testPatternEnabled);
        LinePixelCount counts = newCounts(lineCount, pixelCount);
        lineCount <= counts.line;
        pixelCount <= counts.pixel;

        if (lineCount == 0 && pixelCount == 0)
        begin
            $display("testPatternEnabled %d", shadowTestPatternEnabled);
            testPatternEnabled <= shadowTestPatternEnabled;
        end

        if (hsync == 1)
            dataCount <= 0;
        else if (dataEnable)
            dataCount <= dataCount + 1;
        bramOutStageFifo.enq(Rgb888Stage { vsync: vsync, hsync: hsync, de: dataEnable, pixel: Rgb888{r:0,g:0,b:0}});
        lineBuffer.readAddr(dataCount);
    endrule

    rule bramOutStage;
        bramOutStageFifo.deq;
        let d <- lineBuffer.readData;
        let stageData = bramOutStageFifo.first;

        if (!testPatternEnabled)
            stageData.pixel = unpack(d[23:0]);
        hdmioutput.rgb(Rgb888VideoData{active_video: pack(stageData.de),
            vsync: stageData.vsync, hsync: stageData.hsync,
            r: stageData.pixel.r, g: stageData.pixel.g, b: stageData.pixel.b });
    endrule

    interface hdmi = hdmioutput.hdmi;
    method Action setPatternColor(Bit#(32) v);
        patternReg0 <= v;
    endmethod
    method Action setTestPattern(Bool v);
        shadowTestPatternEnabled <= v;
    endmethod
    method Action setHsyncWidth(Bit#(12) width);
        hsyncWidth <= width;
    endmethod
    method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max);
        dePixelCountMinimum <= min;
        dePixelCountMaximum <= max;
        pixelMidpoint <= (min + max) / 2;
    endmethod
    method Action setVsyncWidth(Bit#(11) width);
        vsyncWidth <= width;
    endmethod
    method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max);
        deLineCountMinimum <= min;
        deLineCountMaximum <= max;
        lineMidpoint <= (min + max) / 2;
    endmethod
    method Action setNumberOfLines(Bit#(11) lines);
        numberOfLines <= lines;
    endmethod
    method Action setNumberOfPixels(Bit#(12) pixels);
        numberOfPixels <= pixels;
    endmethod
endmodule

module mkHdmiOut(HdmiOut);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Reg#(Rgb888Stage) rgb888StageReg <- mkReg(unpack(0));
    Reg#(Yuv444IntermediatesStage) yuv444IntermediatesStageReg <- mkReg(
        Yuv444IntermediatesStage { vsync: 0, hsync: 0, de: False, data: unpack(0) });
    Reg#(Yuv444Stage) yuv444StageReg <- mkReg(
        Yuv444Stage { vsync: 0, hsync: 0, de: False, data: unpack(0) });
    Reg#(Yuv422Stage) yuv422StageReg <- mkReg(
        Yuv422Stage { vsync: 0, hsync: 0, de: False, data: unpack(0) });
    Reg#(Bool) evenOddPixelReg <- mkReg(False);

    rule yuv444IntermediatesStage;
        let previous = rgb888StageReg;
        let pixel = previous.pixel;
        yuv444IntermediatesStageReg <= Yuv444IntermediatesStage {
            vsync: previous.vsync,
            hsync: previous.hsync,
            de: previous.de,
            data: (previous.de) ? rgbToYuvIntermediates(pixel) : unpack(0)
        };
    endrule

    rule yuv444Stage;
        let previous = yuv444IntermediatesStageReg;
        yuv444StageReg <= Yuv444Stage {
            vsync: previous.vsync,
            hsync: previous.hsync,
            de: previous.de,
            data: (previous.de) ? yuvIntermediatesToYuv444(previous.data) : unpack(0)
        };
    endrule

    rule yuv422stage;
        let previous = yuv444StageReg;
        if (previous.de)
            evenOddPixelReg <= !evenOddPixelReg;
        Bit#(16) data = { evenOddPixelReg ? previous.data.u : previous.data.v,
                          previous.data.y };
        yuv422StageReg <= Yuv422Stage {
            vsync: previous.vsync,
            hsync: previous.hsync,
            de: previous.de,
            data: data
        };
    endrule

    method Action rgb(Rgb888VideoData videoData);
        rgb888StageReg <= Rgb888Stage {
            vsync: videoData.vsync,
            hsync: videoData.hsync,
            de: videoData.active_video == 1 ? True : False,
            pixel: Rgb888 { r: videoData.r, g: videoData.g, b: videoData.b}};
    endmethod
    interface HDMI hdmi;
        method Bit#(1) hdmi_vsync;
            return yuv422StageReg.vsync;
        endmethod
        method Bit#(1) hdmi_hsync;
            return yuv422StageReg.hsync;
        endmethod
        method Bit#(1) hdmi_de;
            return yuv422StageReg.de ? 1 : 0;
        endmethod
        method Bit#(16) hdmi_data;
            return yuv422StageReg.data;
        endmethod
        interface hdmi_clock_if = defaultClock;
        interface hdmi_reset_if = defaultReset;
    endinterface
endmodule


simplify sglist

simplify sglist

// 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 RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import MemTypes::*;
import StmtFSM::*;
import ClientServer::*;
import PortalMemory::*;

typedef 32 MaxNumSGLists;
typedef Bit#(TLog#(MaxNumSGLists)) SGListId;
typedef 12 SGListPageShift0;
typedef 16 SGListPageShift4;
typedef 20 SGListPageShift8;
typedef Bit#(TLog#(MaxNumSGLists)) RegionsIdx;
typedef Tuple2#(SGListId,Bit#(ObjectOffsetSize)) ReqTup;

interface SGListMMU#(numeric type addrWidth);
   method Action sglist(Bit#(32) pointer, Bit#(40) paddr, Bit#(32) len);
   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef union tagged{
   Bit#(SGListPageShift0) OOrd0;
   Bit#(SGListPageShift4) OOrd4;
   Bit#(SGListPageShift8) OOrd8;
} Offset deriving (Eq,Bits,FShow);

typedef Bit#(TSub#(ObjectOffsetSize,SGListPageShift0)) Page;

typedef struct {
   Bit#(ObjectOffsetSize) barrier;
   Bit#(8) idxOffset;
   } Region deriving (Eq,Bits,FShow);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

   // stage 0 (latency == 1)
   Vector#(2, FIFO#(ReqTup)) incomingReqs <- replicateM(mkFIFO);

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(ReqTup))            reqs <- replicateM(mkSizedFIFOF(3));

   // stage 2 (latency == 1)
   Vector#(2,FIFOF#(Offset))           offs0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(8)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(8)))     idxOffsets <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))          ptrs <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(3)))      pageSizes <- replicateM(mkFIFOF);

   // stage 3 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page) pages <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(Offset))           offs1 <- replicateM(mkSizedFIFOF(3));

   // stage 4 (latnecy == 1)
   Vector#(2,FIFOF#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFOF);

   let page_shift0 = fromInteger(valueOf(SGListPageShift0));
   let page_shift4 = fromInteger(valueOf(SGListPageShift4));
   let page_shift8 = fromInteger(valueOf(SGListPageShift8));

   let ord0 = 40'd1 << page_shift0;
   let ord4 = 40'd1 << page_shift4;
   let ord8 = 40'd1 << page_shift8;

   function BRAMServer#(a,b) portsel(BRAM2Port#(a,b) x, Integer i);
      if(i==0) return x.portA;
      else return x.portB;
   endfunction

   for (Integer i = 0; i < 2; i=i+1)
      rule stage1;
	 let req <- toGet(incomingReqs[i]).get();
	 match { .ptr, .off } = req;
	 portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr-1), datain:?});
	 portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr-1), datain:?});
	 portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr-1), datain:?});
	 reqs[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;

	 reqs[i].deq;
	 let ptr = tpl_1(reqs[i].first);
	 let off = tpl_2(reqs[i].first);
	 Offset o = tagged OOrd0 0;
	 Bit#(8) pbase = 0;
	 Bit#(8) idxOffset = 0;

	 Bit#(40) barrier8 = region8.barrier;
	 Bit#(40) barrier4 = region4.barrier;
	 Bit#(40) barrier0 = region0.barrier;

	 Bit#(3) pageSize = 0;
	 if (off < barrier8) begin
	    //$display("request: ptr=%h off=%h barrier8=%h", ptr, off, barrier8);
	    o = tagged OOrd8 truncate(off);
	    pbase = truncate(off>>page_shift8);
	    pageSize = 3;
	    idxOffset = region8.idxOffset;
	 end
	 else if (off < barrier4) begin
	    //$display("request: ptr=%h off=%h barrier4=%h", ptr, off, barrier4);
	    o = tagged OOrd4 truncate(off);
	    pbase = truncate(off>>page_shift4);
	    pageSize = 2;
	    idxOffset = region4.idxOffset;
	 end
	 else if (off < barrier0) begin
	    //$display("request: ptr=%h off=%h barrier0=%h", ptr, off, barrier0);
	    o = tagged OOrd0 truncate(off);
	    pbase = truncate(off>>page_shift0);
	    pageSize = 1;
	    idxOffset = region0.idxOffset;
	 end
	 else begin
	    pageSize = 0;
	    //dmaIndication.dmaError(extend(pack(DmaErrorBadAddrTrans)), extend(ptr), extend(off), barrier0);
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets[i].enq(idxOffset);
	 ptrs[i].enq(ptr);
	 pageSizes[i].enq(pageSize);
      endrule
      rule stage3;
	 let off <- toGet(offs0[i]).get();
	 let pbase <- toGet(pbases[i]).get();
	 let idxOffset <- toGet(idxOffsets[i]).get();
	 let ptr <- toGet(ptrs[i]).get();
	 let pageSize <- toGet(pageSizes[i]).get();
	 Bit#(8) p = pbase + idxOffset;
	 if (pageSize == 0) begin
	    //FIXME offset
	    //$display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaIndication.dmaError(extend(pack(DmaErrorBadAddrTrans)), extend(ptr), -1, 0);
	 end
	 //$display("p ages[%d].read %h", i, rp[i].first());
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:{ptr-1,p}, datain:?});
	 offs1[i].enq(off);
      endrule
      rule stage4;
	 let page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 //$display("p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(ObjectOffsetSize) rv = 0;
	 case (offset) matches
	    tagged OOrd0 .o:
		  rv = {truncate(page),o};
	    tagged OOrd4 .o:
		  rv = {truncate(page),o};
	    tagged OOrd8 .o:
		  rv = {truncate(page),o};
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   FIFO#(SGListId) configRespFifo <- mkFIFO;
   rule sendConfigResp;
      let ptr <- toGet(configRespFifo).get();
      dmaIndication.configResp(extend(ptr));
   endrule

   FIFO#(Tuple3#(SGListId,Bit#(40),Bit#(32))) sglistFifo <- mkFIFO();
   Reg#(Bit#(8))                      idxReg <- mkReg(0);
   rule sglistRule;
      match { .ptr, .paddr, .len } <- toGet(sglistFifo).get();

      // $display("sglist(ptr=%d, paddr=%h, len=%h", ptr, paddr,len);
      if (idxReg+1 == 0) begin
	 $display("sglist: exceeded maximun length of sglist");
	 dmaIndication.dmaError(extend(pack(DmaErrorBadNumberEntries)), extend(ptr),extend(len), extend(idxReg));
      end
      else begin
	 if (len == 0) begin
	    idxReg <= 0;
	 end
	 else begin
	    idxReg <= idxReg+1;
	 end
	 configRespFifo.enq(truncate(ptr));
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(ptr-1),idxReg}, datain:truncate(paddr)});
      end
   endrule

   FIFOF#(Tuple4#(RegionsIdx,Region,Region,Region)) regionFifo <- mkSizedFIFOF(1);
   rule regionRule;
      match { .ptr, .region8, .region4, .region0 } <- toGet(regionFifo).get();
      let idx = ptr-1;
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: idx, datain: region8});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: idx, datain: region4});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: idx, datain: region0});
      //$display("region ptr=%d off8=%h off4=%h off0=%h", ptr, off8, off4, off0);
      configRespFifo.enq(ptr);
   endrule

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		incomingReqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   // FIXME: split this into three methods?
   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
      Region region8 = Region { barrier: barr8, idxOffset: off8 };
      Region region4 = Region { barrier: barr4, idxOffset: off4 };
      Region region0 = Region { barrier: barr0, idxOffset: off0 };
      regionFifo.enq(tuple4(truncate(ptr),region8,region4,region0));
   endmethod

   method Action sglist(Bit#(32) ptr, Bit#(40) paddr, Bit#(32) len);
      sglistFifo.enq(tuple3(truncate(ptr), paddr, len));
   endmethod

   interface addr = addrServers;

endmodule

interface SglAddrServer#(numeric type addrWidth, numeric type numServers);
   interface Vector#(numServers,Server#(ReqTup,Bit#(addrWidth))) servers;
endinterface

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(addrWidth,numServers));

   FIFOF#(Bit#(TAdd#(1,TLog#(numServers)))) tokFifo <- mkSizedFIFOF(9);
   Vector#(numServers, Server#(ReqTup,Bit#(addrWidth))) addrServers;
   Reg#(Bit#(TLog#(numServers))) arb <- mkReg(0);

   // this is a very crude arbiter.  something more sophisticated may be required (mdk)
   rule inc_arb;
      arb <= arb+1;
   endrule

   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req) if (arb == fromInteger(i));
		tokFifo.enq(fromInteger(i));
		server.request.put(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get() if (tokFifo.first == fromInteger(i));
		tokFifo.deq;
		let rv <- server.response.get;
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface servers = addrServers;

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 RegFile::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import BRAMFIFO::*;
import BRAM::*;
import MemTypes::*;
import StmtFSM::*;
import ClientServer::*;
import PortalMemory::*;

typedef 32 MaxNumSGLists;
typedef Bit#(TLog#(MaxNumSGLists)) SGListId;
typedef 12 SGListPageShift0;
typedef 16 SGListPageShift4;
typedef 20 SGListPageShift8;
typedef Bit#(TLog#(MaxNumSGLists)) RegionsIdx;
typedef Tuple2#(SGListId,Bit#(ObjectOffsetSize)) ReqTup;

interface SGListMMU#(numeric type addrWidth);
   method Action sglist(Bit#(32) pointer, Bit#(40) paddr, Bit#(32) len);
   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
   interface Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addr;
endinterface

typedef union tagged{
   Bit#(SGListPageShift0) OOrd0;
   Bit#(SGListPageShift4) OOrd4;
   Bit#(SGListPageShift8) OOrd8;
} Offset deriving (Eq,Bits,FShow);

typedef union tagged{
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift0)) POrd0;
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift4)) POrd4;
   Bit#(TSub#(ObjectOffsetSize,SGListPageShift8)) POrd8;
} Page deriving (Eq,Bits,FShow);

typedef struct {
   Bit#(ObjectOffsetSize) barrier;
   Bit#(8) idxOffset;
   } Region deriving (Eq,Bits,FShow);

// the address translation servers (addr[0], addr[1]) have a latency of 8 and are fully pipelined
module mkSGListMMU#(DmaIndication dmaIndication)(SGListMMU#(addrWidth))
   provisos(Log#(MaxNumSGLists, listIdxSize),
	    Add#(listIdxSize,8, entryIdxSize),
	    Add#(c__, addrWidth, ObjectOffsetSize));

   // stage 0 (latency == 1)
   Vector#(2, FIFO#(ReqTup)) incomingReqs <- replicateM(mkFIFO);

   // stage 1 (latency == 2)
   BRAM_Configure bramConfig = defaultValue;
   bramConfig.latency        = 2;
   BRAM2Port#(RegionsIdx, Region)       reg8 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg4 <- mkBRAM2Server(bramConfig);
   BRAM2Port#(RegionsIdx, Region)       reg0 <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(ReqTup))            reqs <- replicateM(mkSizedFIFOF(3));

   // stage 2 (latency == 1)
   Vector#(2,FIFOF#(Offset))           offs0 <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(8)))         pbases <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(8)))     idxOffsets <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(SGListId))          ptrs <- replicateM(mkFIFOF);
   Vector#(2,FIFOF#(Bit#(3)))      pageSizes <- replicateM(mkFIFOF);

   // stage 3 (latency == 2)
   BRAM2Port#(Bit#(entryIdxSize),Page) pages <- mkBRAM2Server(bramConfig);
   Vector#(2,FIFOF#(Offset))           offs1 <- replicateM(mkSizedFIFOF(3));

   // stage 4 (latnecy == 1)
   Vector#(2,FIFOF#(Bit#(addrWidth))) pageResponseFifos <- replicateM(mkFIFOF);

   let page_shift0 = fromInteger(valueOf(SGListPageShift0));
   let page_shift4 = fromInteger(valueOf(SGListPageShift4));
   let page_shift8 = fromInteger(valueOf(SGListPageShift8));

   let ord0 = 40'd1 << page_shift0;
   let ord4 = 40'd1 << page_shift4;
   let ord8 = 40'd1 << page_shift8;

   function BRAMServer#(a,b) portsel(BRAM2Port#(a,b) x, Integer i);
      if(i==0) return x.portA;
      else return x.portB;
   endfunction

   for (Integer i = 0; i < 2; i=i+1)
      rule stage1;
	 let req <- toGet(incomingReqs[i]).get();
	 match { .ptr, .off } = req;
	 portsel(reg8, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr-1), datain:?});
	 portsel(reg4, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr-1), datain:?});
	 portsel(reg0, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:truncate(ptr-1), datain:?});
	 reqs[i].enq(req);
      endrule

   // pipeline the address lookup
   for(Integer i = 0; i < 2; i=i+1) begin
      rule stage2;
	 Region region8 <- portsel(reg8,i).response.get;
	 Region region4 <- portsel(reg4,i).response.get;
	 Region region0 <- portsel(reg0,i).response.get;

	 reqs[i].deq;
	 let ptr = tpl_1(reqs[i].first);
	 let off = tpl_2(reqs[i].first);
	 Offset o = tagged OOrd0 0;
	 Bit#(8) pbase = 0;
	 Bit#(8) idxOffset = 0;

	 Bit#(40) barrier8 = region8.barrier;
	 Bit#(40) barrier4 = region4.barrier;
	 Bit#(40) barrier0 = region0.barrier;

	 Bit#(3) pageSize = 0;
	 if (off < barrier8) begin
	    //$display("request: ptr=%h off=%h barrier8=%h", ptr, off, barrier8);
	    o = tagged OOrd8 truncate(off);
	    pbase = truncate(off>>page_shift8);
	    pageSize = 3;
	    idxOffset = region8.idxOffset;
	 end
	 else if (off < barrier4) begin
	    //$display("request: ptr=%h off=%h barrier4=%h", ptr, off, barrier4);
	    o = tagged OOrd4 truncate(off);
	    pbase = truncate(off>>page_shift4);
	    pageSize = 2;
	    idxOffset = region4.idxOffset;
	 end
	 else if (off < barrier0) begin
	    //$display("request: ptr=%h off=%h barrier0=%h", ptr, off, barrier0);
	    o = tagged OOrd0 truncate(off);
	    pbase = truncate(off>>page_shift0);
	    pageSize = 1;
	    idxOffset = region0.idxOffset;
	 end
	 else begin
	    pageSize = 0;
	    //dmaIndication.dmaError(extend(pack(DmaErrorBadAddrTrans)), extend(ptr), extend(off), barrier0);
	 end
	 offs0[i].enq(o);
	 pbases[i].enq(pbase);
	 idxOffsets[i].enq(idxOffset);
	 ptrs[i].enq(ptr);
	 pageSizes[i].enq(pageSize);
      endrule
      rule stage3;
	 let off <- toGet(offs0[i]).get();
	 let pbase <- toGet(pbases[i]).get();
	 let idxOffset <- toGet(idxOffsets[i]).get();
	 let ptr <- toGet(ptrs[i]).get();
	 let pageSize <- toGet(pageSizes[i]).get();
	 Bit#(8) p = pbase + idxOffset;
	 if (pageSize == 0) begin
	    //FIXME offset
	    //$display("mkSGListMMU.addr[%d].request.put: ERROR   ptr=%h off=%h\n", i, ptr, off);
	    dmaIndication.dmaError(extend(pack(DmaErrorBadAddrTrans)), extend(ptr), -1, 0);
	 end
	 //$display("p ages[%d].read %h", i, rp[i].first());
	 portsel(pages, i).request.put(BRAMRequest{write:False, responseOnWrite:False,
            address:{ptr-1,p}, datain:?});
	 offs1[i].enq(off);
      endrule
      rule stage4;
	 let page <- portsel(pages, i).response.get;
	 let offset <- toGet(offs1[i]).get();
	 //$display("p ages[%d].response page=%h offset=%h", i, page, offset);
	 Bit#(ObjectOffsetSize) rv = 0;
	 case (offset) matches
	    tagged OOrd0 .o:
	       begin
		  case (page) matches
		     tagged POrd4 .p:
			$display("OOrd0 vs POrd4");
		     tagged POrd8 .p:
			$display("OOrd0 vs POrd8");
		  endcase
		  rv = {page.POrd0,o};
	       end
	    tagged OOrd4 .o:
	       begin
		  case (page) matches
		     tagged POrd0 .p:
			$display("OOrd4 vs POrd0");
		     tagged POrd8 .p:
			$display("OOrd4 vs POrd8");
		  endcase
		  rv = {page.POrd4,o};
	       end
	    tagged OOrd8 .o:
	       begin
		  case (page) matches
		     tagged POrd0 .p:
			$display("OOrd8 vs POrd0");
		     tagged POrd4 .p:
			$display("OOrd8 vs POrd4");
		  endcase
		  rv = {page.POrd8,o};
	       end
	 endcase
	 pageResponseFifos[i].enq(truncate(rv));
      endrule
   end

   FIFO#(SGListId) configRespFifo <- mkFIFO;
   rule sendConfigResp;
      let ptr <- toGet(configRespFifo).get();
      dmaIndication.configResp(extend(ptr));
   endrule

   FIFO#(Tuple3#(SGListId,Bit#(40),Bit#(32))) sglistFifo <- mkFIFO();
   Reg#(Bit#(8))                      idxReg <- mkReg(0);
   rule sglistRule;
      match { .ptr, .paddr, .len } <- toGet(sglistFifo).get();

      // $display("sglist(ptr=%d, paddr=%h, len=%h", ptr, paddr,len);
      if (idxReg+1 == 0) begin
	 $display("sglist: exceeded maximun length of sglist");
	 dmaIndication.dmaError(extend(pack(DmaErrorBadNumberEntries)), extend(ptr),extend(len), extend(idxReg));
      end
      else begin
	 Page page = tagged POrd0 0;
	 if (len == 0) begin
	    idxReg <= 0;
	 end
	 else begin
	    idxReg <= idxReg+1;
	    if (extend(len) == ord0) begin
	       page = tagged POrd0 truncate(paddr); //>>page_shift0);
	    end
	    else if (extend(len) == ord4) begin
	       page = tagged POrd4 truncate(paddr); //>>page_shift4);
	    end
	    else if (extend(len) == ord8) begin
	       page = tagged POrd8 truncate(paddr); //>>page_shift8);
	    end
	    else begin
	       $display("mkSGListMMU::sglist unsupported length %h", len);
	       dmaIndication.dmaError(extend(pack(DmaErrorBadPageSize)), extend(ptr), extend(len), 0);
	    end
	 end
	 configRespFifo.enq(truncate(ptr));
	 portsel(pages, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
             address:{truncate(ptr-1),idxReg}, datain:page});
      end
   endrule

   FIFOF#(Tuple4#(RegionsIdx,Region,Region,Region)) regionFifo <- mkSizedFIFOF(1);
   rule regionRule;
      match { .ptr, .region8, .region4, .region0 } <- toGet(regionFifo).get();
      let idx = ptr-1;
      portsel(reg8, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: idx, datain: region8});
      portsel(reg4, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: idx, datain: region4});
      portsel(reg0, 0).request.put(BRAMRequest{write:True, responseOnWrite:False,
          address: idx, datain: region0});
      //$display("region ptr=%d off8=%h off4=%h off0=%h", ptr, off8, off4, off0);
      configRespFifo.enq(ptr);
   endrule

   Vector#(2,Server#(ReqTup,Bit#(addrWidth))) addrServers;
   for(Integer i = 0; i < 2; i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req);
		incomingReqs[i].enq(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get();
		let rv <- toGet(pageResponseFifos[i]).get();
		return rv;
	     endmethod
	  endinterface
       endinterface);

   // FIXME: split this into three methods?
   method Action region(Bit#(32) ptr, Bit#(40) barr8, Bit#(8) off8, Bit#(40) barr4, Bit#(8) off4, Bit#(40) barr0, Bit#(8) off0);
      Region region8 = Region { barrier: barr8, idxOffset: off8 };
      Region region4 = Region { barrier: barr4, idxOffset: off4 };
      Region region0 = Region { barrier: barr0, idxOffset: off0 };
      regionFifo.enq(tuple4(truncate(ptr),region8,region4,region0));
   endmethod

   method Action sglist(Bit#(32) ptr, Bit#(40) paddr, Bit#(32) len);
      sglistFifo.enq(tuple3(truncate(ptr), paddr, len));
   endmethod

   interface addr = addrServers;

endmodule

interface SglAddrServer#(numeric type addrWidth, numeric type numServers);
   interface Vector#(numServers,Server#(ReqTup,Bit#(addrWidth))) servers;
endinterface

module mkSglAddrServer#(Server#(ReqTup,Bit#(addrWidth)) server) (SglAddrServer#(addrWidth,numServers));

   FIFOF#(Bit#(TAdd#(1,TLog#(numServers)))) tokFifo <- mkSizedFIFOF(9);
   Vector#(numServers, Server#(ReqTup,Bit#(addrWidth))) addrServers;
   Reg#(Bit#(TLog#(numServers))) arb <- mkReg(0);

   // this is a very crude arbiter.  something more sophisticated may be required (mdk)
   rule inc_arb;
      arb <= arb+1;
   endrule

   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      addrServers[i] =
      (interface Server#(ReqTup,Bit#(addrWidth));
	  interface Put request;
	     method Action put(ReqTup req) if (arb == fromInteger(i));
		tokFifo.enq(fromInteger(i));
		server.request.put(req);
	     endmethod
	  endinterface
	  interface Get response;
	     method ActionValue#(Bit#(addrWidth)) get() if (tokFifo.first == fromInteger(i));
		tokFifo.deq;
		let rv <- server.response.get;
		return rv;
	     endmethod
	  endinterface
       endinterface);

   interface servers = addrServers;

endmodule


make latency conditions in SimDma '>=' instead of '>' (so that expected latency matches numeric value specified)

// Copyright (c) 2015 Connectal Project

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

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

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

import Vector::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;

import MemTypes::*;

`ifdef SIM_DMA_READ_LATENCY
typedef `SIM_DMA_READ_LATENCY SimDmaReadLatency;
`else
typedef 150 SimDmaReadLatency;
`endif
`ifdef SIM_DMA_WRITE_LATENCY
typedef `SIM_DMA_WRITE_LATENCY SimDmaWriteLatency;
`else
typedef 150 SimDmaWriteLatency;
`endif

interface SimDma#(numeric type dataWidth);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action idreturn(Bit#(32) id);
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(dataWidth)) readresponse();
endinterface

`ifdef BSIM
import "BDPI" function ActionValue#(Bit#(32)) simDma_init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
import "BDPI" function ActionValue#(Bit#(32)) simDma_initfd(Bit#(32) id, Bit#(32) fd);
import "BDPI" function ActionValue#(Bit#(32)) simDma_idreturn(Bit#(32) id);

// implemented in BsimDma.cpp
import "BDPI" function Action write_simDma32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_simDma64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_simDma32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_simDma64(Bit#(32) handle, Bit#(32) addr);

module mkSimDma(SimDma#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   FIFO#(Bit#(dataWidth)) dataFifo <- mkFIFO();
      method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
	 let v <- simDma_init(id, handle, size);
	 //return v;
      endmethod
      method Action initfd(Bit#(32) id, Bit#(32) fd);
	 let v <- simDma_initfd(id, fd);
	 //return v;
      endmethod
      method Action idreturn(Bit#(32) id);
	 let v <- simDma_idreturn(id);
	 //return v;
      endmethod
      method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
	  Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
	  function Action write32(Integer i, Bit#(32) vv);
	     action
		write_simDma32(handle, addr+4*fromInteger(i), vv);
	     endaction
	  endfunction
	  mapM_(uncurry(write32), zip(genVector(), vs));
      endmethod
      method Action  readrequest(Bit#(32) handle, Bit#(32) addr);
	  function ActionValue#(Bit#(32)) read32(Integer i);
	     actionvalue
		let v <- read_simDma32(handle, addr+4*fromInteger(i));
		return v;
	     endactionvalue
	  endfunction
   	  Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(read32, genVector());
	  dataFifo.enq(pack(vs));
      endmethod
      method ActionValue#(Bit#(dataWidth)) readresponse();
          let v <- toGet(dataFifo).get();
	  return v;
      endmethod
endmodule
`endif

`ifdef XSIM
interface XsimDmaReadWrite;
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action idreturn(Bit#(32) id);
   method Action write32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(32)) readresponse();
endinterface

import "BVI" XsimDmaReadWrite =
module mkXsimReadWrite(XsimDmaReadWrite);
   method init(init_id, init_handle, init_size) enable (en_init);
   method initfd(initfd_id, initfd_fd) enable (en_initfd);
   method idreturn(idreturn_id) enable (en_idreturn);
   method write32(write32_handle, write32_addr, write32_data) enable (en_write32);
   method readrequest(readrequest_handle, readrequest_addr) enable (en_readrequest) ready (rdy_readrequest);
   method readresponse_data readresponse() enable (en_readresponse) ready (rdy_readresponse);
   schedule (init, initfd, write32, readrequest, readresponse, idreturn) CF (init, initfd, write32, readrequest, readresponse, idreturn);
endmodule

module mkSimDma(SimDma#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   Vector#(TDiv#(dataWidth,32),XsimDmaReadWrite) rws <- replicateM(mkXsimReadWrite());
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
      rws[0].init(id, handle, size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
      rws[0].initfd(id, fd);
   endmethod
   method Action idreturn(Bit#(32) id);
      rws[0].idreturn(id);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
      Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
      function Action write32(Integer i, Bit#(32) vv);
	 action
	    rws[i].write32(handle, addr+4*fromInteger(i), vv);
	 endaction
      endfunction
      mapM_(uncurry(write32), zip(genVector(), vs));
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
      function Action doreadrequest(Integer i);
	 action
	    rws[i].readrequest(handle, addr+4*fromInteger(i));
	 endaction
      endfunction
      Vector#(TDiv#(dataWidth,32),Integer) indexes = genVector();
      mapM_(doreadrequest, indexes);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      function ActionValue#(Bit#(32)) readresponse32(Integer i);
	 actionvalue
	    let v <- rws[i].readresponse();
	    return v;
	 endactionvalue
      endfunction
      Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(readresponse32, genVector());
      return pack(vs);
   endmethod
endmodule
`endif

`ifndef BSIM
`ifndef XSIM
module mkSimDma(SimDma#(dataWidth) ifc);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   endmethod
   method Action idreturn(Bit#(32) id);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      return 0;
   endmethod
endmodule
`endif
`endif

module mkSimDmaDmaMaster(PhysMemSlave#(serverAddrWidth,serverBusWidth))
   provisos(Div#(serverBusWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,serverBusWidth),
	    Log#(dataWidthBytes,beatShift),
	    Mul#(TDiv#(serverBusWidth, 32), 32, serverBusWidth),
	    Bits#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)), a__)
	    );

   let verbose = False;
   SimDma#(serverBusWidth) rw <- mkSimDma();

   Reg#(Bit#(BurstLenSize))  readLenReg <- mkReg(0);
   Reg#(Bit#(32))         readOffsetReg <- mkReg(0);

   Reg#(Bit#(BurstLenSize))  writeLenReg <- mkReg(0);
   Reg#(Bit#(32))         writeOffsetReg <- mkReg(0);

   let readLatency_I = valueOf(SimDmaReadLatency);
   let writeLatency_I = valueOf(SimDmaWriteLatency);

   Bit#(64) readLatency = fromInteger(readLatency_I);
   Bit#(64) writeLatency = fromInteger(writeLatency_I);

   Reg#(Bit#(64)) req_ar_b_ts <- mkReg(0);
   Reg#(Bit#(64)) req_aw_b_ts <- mkReg(0);
   Reg#(Bit#(64)) cycles <- mkReg(0);
   Reg#(Bit#(64)) last_reqAr <- mkReg(0);
   Reg#(Bit#(64)) last_read_eob <- mkReg(0);
   Reg#(Bit#(64)) last_write_eob <- mkReg(0);

   FIFOF#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)))  readDelayFifo <- mkSizedFIFOF(readLatency_I);
   FIFOF#(Tuple2#(Bit#(64),PhysMemRequest#(serverAddrWidth))) writeDelayFifo <- mkSizedFIFOF(writeLatency_I);

   FIFOF#(Tuple2#(Bit#(64), Bit#(MemTagSize))) bFifo <- mkSizedFIFOF(writeLatency_I);
   FIFOF#(Tuple2#(Bit#(MemTagSize),Bool)) taglastfifo <- mkFIFOF();
   rule increment_cycle;
      cycles <= cycles+1;
   endrule

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

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Bit#(8)) reqs <- mkSizedFIFO(32);

   let beat_shift = fromInteger(valueOf(beatShift));

   rule read_rule if (readDelayFifo.notEmpty() && (cycles-tpl_1(readDelayFifo.first) >= readLatency));
	 match { .reqTime, .req } = readDelayFifo.first;
	 Bit#(BurstLenSize) readLen = readLenReg;
	 Bit#(32) readOffset = readOffsetReg;
	 Bit#(MemTagSize) tag = req.tag;
	 Bit#(8) handle = req.addr[39:32];

	 if (readLen == 0) begin
	    req_ar_b_ts <= cycles;
	    readLen     = req.burstLen>>beat_shift;
	    readOffset  = 0;
	 end
	 rw.readrequest(extend(handle), req.addr[31:0]+readOffset);
	 let last = (readLen == 1);
	 if (last)
	    readDelayFifo.deq();
	 taglastfifo.enq(tuple2(tag, last));
	 readLenReg <= readLen - 1;
	 readOffsetReg <= readOffset + fromInteger(valueOf(serverBusWidth)/8);
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
            if (verbose) $display("mkSimDmaDmaMaster::%d axiSlave.read.readAddr %h bc %d", cycles, req.addr, req.burstLen);
	    //readAddrGenerator.request.put(req);
	    readDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(serverBusWidth)) get();
	     match { .tag, .last } <- toGet(taglastfifo).get();
 	     let v <- rw.readresponse();
 	     //if (verbose) $display("mkSimDmaDmaMaster::%d axiSlave.read.readData %h tag %d last %d", cycles, v, tag, last);
	     return MemData { data: v, tag: tag, last: last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
	 //$display("mkSimDmaDmaMaster::req_aw id=%d", req.tag);
	 writeDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Put writeData;
	 method Action put(MemData#(serverBusWidth) resp) if (writeDelayFifo.notEmpty && (cycles-tpl_1(writeDelayFifo.first)) >= writeLatency);
	    match { .reqTime, .req } = writeDelayFifo.first;
	    Bit#(BurstLenSize) writeLen = writeLenReg;
	    Bit#(32) writeOffset = writeOffsetReg;
	    Bit#(MemTagSize) tag = req.tag;
	    Bit#(8) handle = req.addr[39:32];
	    if (writeLenReg == 0) begin
	       req_aw_b_ts <= cycles;
	       writeLen = req.burstLen>>beat_shift;
	       writeOffset = 0;
	    end
	    rw.write(extend(handle), req.addr[31:0] + writeOffset, resp.data);
	    writeLenReg <= writeLen - 1;
	    writeOffsetReg <= writeOffset + fromInteger(valueOf(serverBusWidth)/8);
	    if (writeLen == 1) begin
	       bFifo.enq(tuple2(cycles,tag));
	       writeDelayFifo.deq;
	    end
	 endmethod
      endinterface
      interface Get writeDone;
	 method ActionValue#(Bit#(MemTagSize)) get() if ((cycles-tpl_1(bFifo.first)) >= writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
	 endmethod
      endinterface
   endinterface
endmodule

// Copyright (c) 2015 Connectal Project

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

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

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

import Vector::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;

import MemTypes::*;

`ifdef SIM_DMA_READ_LATENCY
typedef `SIM_DMA_READ_LATENCY SimDmaReadLatency;
`else
typedef 150 SimDmaReadLatency;
`endif
`ifdef SIM_DMA_WRITE_LATENCY
typedef `SIM_DMA_WRITE_LATENCY SimDmaWriteLatency;
`else
typedef 150 SimDmaWriteLatency;
`endif

interface SimDma#(numeric type dataWidth);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action idreturn(Bit#(32) id);
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(dataWidth)) readresponse();
endinterface

`ifdef BSIM
import "BDPI" function ActionValue#(Bit#(32)) simDma_init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
import "BDPI" function ActionValue#(Bit#(32)) simDma_initfd(Bit#(32) id, Bit#(32) fd);
import "BDPI" function ActionValue#(Bit#(32)) simDma_idreturn(Bit#(32) id);

// implemented in BsimDma.cpp
import "BDPI" function Action write_simDma32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_simDma64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_simDma32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_simDma64(Bit#(32) handle, Bit#(32) addr);

module mkSimDma(SimDma#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   FIFO#(Bit#(dataWidth)) dataFifo <- mkFIFO();
      method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
	 let v <- simDma_init(id, handle, size);
	 //return v;
      endmethod
      method Action initfd(Bit#(32) id, Bit#(32) fd);
	 let v <- simDma_initfd(id, fd);
	 //return v;
      endmethod
      method Action idreturn(Bit#(32) id);
	 let v <- simDma_idreturn(id);
	 //return v;
      endmethod
      method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
	  Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
	  function Action write32(Integer i, Bit#(32) vv);
	     action
		write_simDma32(handle, addr+4*fromInteger(i), vv);
	     endaction
	  endfunction
	  mapM_(uncurry(write32), zip(genVector(), vs));
      endmethod
      method Action  readrequest(Bit#(32) handle, Bit#(32) addr);
	  function ActionValue#(Bit#(32)) read32(Integer i);
	     actionvalue
		let v <- read_simDma32(handle, addr+4*fromInteger(i));
		return v;
	     endactionvalue
	  endfunction
   	  Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(read32, genVector());
	  dataFifo.enq(pack(vs));
      endmethod
      method ActionValue#(Bit#(dataWidth)) readresponse();
          let v <- toGet(dataFifo).get();
	  return v;
      endmethod
endmodule
`endif

`ifdef XSIM
interface XsimDmaReadWrite;
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   method Action idreturn(Bit#(32) id);
   method Action write32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   method ActionValue#(Bit#(32)) readresponse();
endinterface

import "BVI" XsimDmaReadWrite =
module mkXsimReadWrite(XsimDmaReadWrite);
   method init(init_id, init_handle, init_size) enable (en_init);
   method initfd(initfd_id, initfd_fd) enable (en_initfd);
   method idreturn(idreturn_id) enable (en_idreturn);
   method write32(write32_handle, write32_addr, write32_data) enable (en_write32);
   method readrequest(readrequest_handle, readrequest_addr) enable (en_readrequest) ready (rdy_readrequest);
   method readresponse_data readresponse() enable (en_readresponse) ready (rdy_readresponse);
   schedule (init, initfd, write32, readrequest, readresponse, idreturn) CF (init, initfd, write32, readrequest, readresponse, idreturn);
endmodule

module mkSimDma(SimDma#(dataWidth) ifc)
   provisos (Mul#(TDiv#(dataWidth, 32), 32, dataWidth));
   Vector#(TDiv#(dataWidth,32),XsimDmaReadWrite) rws <- replicateM(mkXsimReadWrite());
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
      rws[0].init(id, handle, size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
      rws[0].initfd(id, fd);
   endmethod
   method Action idreturn(Bit#(32) id);
      rws[0].idreturn(id);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
      Vector#(TDiv#(dataWidth, 32), Bit#(32)) vs = unpack(v);
      function Action write32(Integer i, Bit#(32) vv);
	 action
	    rws[i].write32(handle, addr+4*fromInteger(i), vv);
	 endaction
      endfunction
      mapM_(uncurry(write32), zip(genVector(), vs));
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
      function Action doreadrequest(Integer i);
	 action
	    rws[i].readrequest(handle, addr+4*fromInteger(i));
	 endaction
      endfunction
      Vector#(TDiv#(dataWidth,32),Integer) indexes = genVector();
      mapM_(doreadrequest, indexes);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      function ActionValue#(Bit#(32)) readresponse32(Integer i);
	 actionvalue
	    let v <- rws[i].readresponse();
	    return v;
	 endactionvalue
      endfunction
      Vector#(TDiv#(dataWidth,32),Bit#(32)) vs <- mapM(readresponse32, genVector());
      return pack(vs);
   endmethod
endmodule
`endif

`ifndef BSIM
`ifndef XSIM
module mkSimDma(SimDma#(dataWidth) ifc);
   method Action init(Bit#(32) id, Bit#(32) handle, Bit#(32) size);
   endmethod
   method Action initfd(Bit#(32) id, Bit#(32) fd);
   endmethod
   method Action idreturn(Bit#(32) id);
   endmethod
   method Action write(Bit#(32) handle, Bit#(32) addr, Bit#(dataWidth) v);
   endmethod
   method Action readrequest(Bit#(32) handle, Bit#(32) addr);
   endmethod
   method ActionValue#(Bit#(dataWidth)) readresponse();
      return 0;
   endmethod
endmodule
`endif
`endif

module mkSimDmaDmaMaster(PhysMemSlave#(serverAddrWidth,serverBusWidth))
   provisos(Div#(serverBusWidth,8,dataWidthBytes),
	    Mul#(dataWidthBytes,8,serverBusWidth),
	    Log#(dataWidthBytes,beatShift),
	    Mul#(TDiv#(serverBusWidth, 32), 32, serverBusWidth),
	    Bits#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)), a__)
	    );

   let verbose = False;
   SimDma#(serverBusWidth) rw <- mkSimDma();

   Reg#(Bit#(BurstLenSize))  readLenReg <- mkReg(0);
   Reg#(Bit#(32))         readOffsetReg <- mkReg(0);

   Reg#(Bit#(BurstLenSize))  writeLenReg <- mkReg(0);
   Reg#(Bit#(32))         writeOffsetReg <- mkReg(0);

   let readLatency_I = valueOf(SimDmaReadLatency);
   let writeLatency_I = valueOf(SimDmaWriteLatency);

   Bit#(64) readLatency = fromInteger(readLatency_I);
   Bit#(64) writeLatency = fromInteger(writeLatency_I);

   Reg#(Bit#(64)) req_ar_b_ts <- mkReg(0);
   Reg#(Bit#(64)) req_aw_b_ts <- mkReg(0);
   Reg#(Bit#(64)) cycles <- mkReg(0);
   Reg#(Bit#(64)) last_reqAr <- mkReg(0);
   Reg#(Bit#(64)) last_read_eob <- mkReg(0);
   Reg#(Bit#(64)) last_write_eob <- mkReg(0);

   FIFOF#(Tuple2#(Bit#(64), PhysMemRequest#(serverAddrWidth)))  readDelayFifo <- mkSizedFIFOF(readLatency_I);
   FIFOF#(Tuple2#(Bit#(64),PhysMemRequest#(serverAddrWidth))) writeDelayFifo <- mkSizedFIFOF(writeLatency_I);

   FIFOF#(Tuple2#(Bit#(64), Bit#(MemTagSize))) bFifo <- mkSizedFIFOF(writeLatency_I);
   FIFOF#(Tuple2#(Bit#(MemTagSize),Bool)) taglastfifo <- mkFIFOF();
   rule increment_cycle;
      cycles <= cycles+1;
   endrule

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

   Reg#(Bit#(8))  burstReg <- mkReg(0);
   FIFO#(Bit#(8)) reqs <- mkSizedFIFO(32);

   let beat_shift = fromInteger(valueOf(beatShift));

   rule read_rule if (readDelayFifo.notEmpty() && (cycles-tpl_1(readDelayFifo.first) > readLatency));
	 match { .reqTime, .req } = readDelayFifo.first;
	 Bit#(BurstLenSize) readLen = readLenReg;
	 Bit#(32) readOffset = readOffsetReg;
	 Bit#(MemTagSize) tag = req.tag;
	 Bit#(8) handle = req.addr[39:32];

	 if (readLen == 0) begin
	    req_ar_b_ts <= cycles;
	    readLen     = req.burstLen>>beat_shift;
	    readOffset  = 0;
	 end
	 rw.readrequest(extend(handle), req.addr[31:0]+readOffset);
	 let last = (readLen == 1);
	 if (last)
	    readDelayFifo.deq();
	 taglastfifo.enq(tuple2(tag, last));
	 readLenReg <= readLen - 1;
	 readOffsetReg <= readOffset + fromInteger(valueOf(serverBusWidth)/8);
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
            if (verbose) $display("mkSimDmaDmaMaster::%d axiSlave.read.readAddr %h bc %d", cycles, req.addr, req.burstLen);
	    //readAddrGenerator.request.put(req);
	    readDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(serverBusWidth)) get();
	     match { .tag, .last } <- toGet(taglastfifo).get();
 	     let v <- rw.readresponse();
 	     //if (verbose) $display("mkSimDmaDmaMaster::%d axiSlave.read.readData %h tag %d last %d", cycles, v, tag, last);
	     return MemData { data: v, tag: tag, last: last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
	 method Action put(PhysMemRequest#(serverAddrWidth) req);
	 //$display("mkSimDmaDmaMaster::req_aw id=%d", req.tag);
	 writeDelayFifo.enq(tuple2(cycles,req));
	 endmethod
      endinterface
      interface Put writeData;
	 method Action put(MemData#(serverBusWidth) resp) if (writeDelayFifo.notEmpty && (cycles-tpl_1(writeDelayFifo.first)) > writeLatency);
	    match { .reqTime, .req } = writeDelayFifo.first;
	    Bit#(BurstLenSize) writeLen = writeLenReg;
	    Bit#(32) writeOffset = writeOffsetReg;
	    Bit#(MemTagSize) tag = req.tag;
	    Bit#(8) handle = req.addr[39:32];
	    if (writeLenReg == 0) begin
	       req_aw_b_ts <= cycles;
	       writeLen = req.burstLen>>beat_shift;
	       writeOffset = 0;
	    end
	    rw.write(extend(handle), req.addr[31:0] + writeOffset, resp.data);
	    writeLenReg <= writeLen - 1;
	    writeOffsetReg <= writeOffset + fromInteger(valueOf(serverBusWidth)/8);
	    if (writeLen == 1) begin
	       bFifo.enq(tuple2(cycles,tag));
	       writeDelayFifo.deq;
	    end
	 endmethod
      endinterface
      interface Get writeDone;
	 method ActionValue#(Bit#(MemTagSize)) get() if ((cycles-tpl_1(bFifo.first)) > writeLatency);
	 bFifo.deq();
	 return tpl_2(bFifo.first());
	 endmethod
      endinterface
   endinterface
endmodule