simplify patternIndex calculation

simplify patternIndex calculation

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

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

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

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

import Vector::*;
import Clocks::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import GetPut::*;
import SyncBits::*;
import YUV::*;

`ifdef ZC706
typedef 24 HdmiBits;
`else
typedef 16 HdmiBits;
`endif

interface HDMI#(type pixelType);
    method Bit#(1) hdmi_vsync;
    method Bit#(1) hdmi_hsync;
    method Bit#(1) hdmi_de;
    method pixelType hdmi_data;
    interface Clock hdmi_clock_if;
    interface Reset deleteme_unused_reset;
endinterface

interface HdmiInternalRequest;
    method Action setTestPattern(Bit#(1) v);
    method Action setPatternColor(Bit#(32) v);
    method Action setHsyncWidth(Bit#(12) hsyncWidth);
    method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max, Bit#(12) mid);
    method Action setVsyncWidth(Bit#(11) vsyncWidth);
    method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max, Bit#(11) mid);
    method Action setNumberOfLines(Bit#(11) lines);
    method Action setNumberOfPixels(Bit#(12) pixels);
    method Action waitForVsync(Bit#(32) unused);
endinterface
interface HdmiInternalIndication;
    method Action vsync(Bit#(64) v, Bit#(32) vs);
endinterface
interface HdmiInternalStatus;
    method Bit#(11) getNumberOfLines();
    method Bit#(12) getNumberOfPixels();
    method Bool dataEnable();
endinterface

interface HdmiGenerator#(type pixelType);
    interface HdmiInternalRequest control;
    interface HdmiInternalStatus  status;
    interface Get#(VideoData#(pixelType)) rgb888;
    interface Put#(Bit#(32)) request;
endinterface

module mkHdmiGenerator#(Clock axi_clock, Reset axi_reset,
   SyncPulseIfc vsyncPulse, HdmiInternalIndication indication)(HdmiGenerator#(Rgb888));
    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);
    Vector#(4, Reg#(Bit#(24))) patternRegs <- replicateM(mkSyncReg(24'h00FFFFFF, axi_clock, axi_reset, defaultClock));
    Reg#(Bit#(1)) patternIndex0 <- mkReg(0);
    Reg#(Bit#(1)) patternIndex1 <- mkReg(0);
    Reg#(Bit#(1)) shadowTestPatternEnabled <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) testPatternEnabled <- mkReg(1);
    Reg#(Bool) waitingForVsync <- mkSyncReg(False, axi_clock, axi_reset, defaultClock);
    SyncPulseIfc vsyncCountPulse <- mkSyncHandshake(defaultClock, defaultReset, axi_clock);
    SyncPulseIfc sendVsyncIndication <- mkSyncHandshake(defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(24)) pixelData <- mkReg(24'hFF00FF);
    FIFOF#(Bit#(24)) pixelFifo <- mkLFIFOF();

    Reg#(VideoData#(Rgb888)) rgb888StageReg <- mkReg(unpack(0));
    Reg#(Bool) evenOddPixelReg <- mkReg(False);

    Reg#(Bit#(32)) underflowCount <- mkReg(0);
    Reg#(Bit#(32)) underflowCountAxi <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(32)) counter <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    Reg#(Bit#(32)) vsyncCounter <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    Reg#(Bit#(32)) elapsed <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    Reg#(Bit#(32)) elapsedVsync <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    rule axicyclecount;
       counter <= counter + 1;
    endrule

    rule vsyncCount if (vsyncCountPulse.pulse());
       vsyncCounter <= vsyncCounter+1;
    endrule
    rule vsyncReceived if (sendVsyncIndication.pulse());
       elapsed <= counter;
       elapsedVsync <= vsyncCounter;
       indication.vsync(extend(counter - elapsed), extend(vsyncCounter - elapsedVsync));
       waitingForVsync <= False;
    endrule

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

    rule inc_counters;
        if (lineCount == 0 && pixelCount == 0) begin
	    vsyncCountPulse.send();
            vsyncPulse.send();
            if (waitingForVsync) begin
	       sendVsyncIndication.send();
	    end
            testPatternEnabled <= shadowTestPatternEnabled;
        end
        if (pixelCount == numberOfPixels-1) begin
           pixelCount <= 0;
           patternIndex0 <= 0;
           if (lineCount == numberOfLines-1) begin
               lineCount <= 0;
               patternIndex1 <= 0;
           end
           else begin
               lineCount <= lineCount+1;
               if (lineCount >= lineMidpoint)
                   patternIndex1 <= 1;
           end
        end
        else begin
           pixelCount <= pixelCount + 1;
           if (pixelCount >= pixelMidpoint)
               patternIndex0 <= 1;
        end
    endrule

        let isActiveLine = (lineCount >= deLineCountMinimum && lineCount < deLineCountMaximum);
        let dataEnable = (pixelCount >= dePixelCountMinimum && pixelCount < dePixelCountMaximum && isActiveLine);
    rule output_data_rule;
        let hsync = (pixelCount < hsyncWidth) ? 1 : 0;
        let vsync = (lineCount < vsyncWidth) ? 1 : 0;
       Rgb888 pixel = unpack(0);
       if (dataEnable) begin
	   pixel = unpack(pixelData);
       end
        rgb888StageReg <= VideoData {de: pack(dataEnable),
				     vsync: vsync, hsync: hsync, pixel: pixel };
    endrule

    rule testpattern_rule if (testPatternEnabled != 0);
       pixelData <= patternRegs[{patternIndex1, patternIndex0}];
    endrule

    interface Put request;
        method Action put(Bit#(32) v) if (testPatternEnabled == 0 && dataEnable);
	   pixelData <= v[23:0];
        endmethod
    endinterface: request

    interface HdmiInternalStatus status;
	method Bit#(11) getNumberOfLines();
	   return numberOfLines;
	endmethod
	method Bit#(12) getNumberOfPixels();
	   return numberOfPixels;
	endmethod
   method Bool dataEnable();
        let isActiveLine = (lineCount >= deLineCountMinimum && lineCount < deLineCountMaximum);
      return (pixelCount >= dePixelCountMinimum && pixelCount < dePixelCountMaximum && isActiveLine);
   endmethod

    endinterface
    interface HdmiInternalRequest control;
        method Action setPatternColor(Bit#(32) v);
            patternRegs[0] <= v[23:0];
        endmethod
        method Action setTestPattern(Bit#(1) v);
            shadowTestPatternEnabled <= v;
        endmethod
        method Action setHsyncWidth(Bit#(12) width);
            hsyncWidth <= width;
        endmethod
        method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max, Bit#(12) mid);
            dePixelCountMinimum <= min;
            dePixelCountMaximum <= max;
            pixelMidpoint <= mid;
        endmethod
        method Action setVsyncWidth(Bit#(11) width);
            vsyncWidth <= width;
        endmethod
        method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max, Bit#(11) mid);
            deLineCountMinimum <= min;
            deLineCountMaximum <= max;
            lineMidpoint <= mid;
        endmethod
        method Action setNumberOfLines(Bit#(11) lines);
            numberOfLines <= lines;
        endmethod
        method Action setNumberOfPixels(Bit#(12) pixels);
            numberOfPixels <= pixels;
        endmethod
        method Action waitForVsync(Bit#(32) unused);
            waitingForVsync <= True;
        endmethod
    endinterface
   interface Get rgb888;
      method ActionValue#(VideoData#(Rgb888)) get();
	 return rgb888StageReg;
      endmethod
   endinterface
endmodule

module mkHDMI#(Get#(VideoData#(pixelType)) videoInput)(HDMI#(Bit#(pixelsz)))
   provisos (Bits#(VideoData#(pixelType), a__), Bits#(pixelType,pixelsz));
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   Wire#(VideoData#(pixelType)) video <- mkDWire(unpack(0));
   rule getvideo;
      let v <- videoInput.get();
      video <= v;
   endrule

   method Bit#(1) hdmi_vsync;
      return video.vsync;
   endmethod
   method Bit#(1) hdmi_hsync;
      return video.hsync;
   endmethod
   method Bit#(1) hdmi_de;
      return video.de;
   endmethod
   method Bit#(pixelsz) hdmi_data;
      return pack(video.pixel);
   endmethod
   interface hdmi_clock_if = defaultClock;
   interface deleteme_unused_reset = defaultReset;
endmodule

interface Rgb888ToYyuv;
   interface Put#(VideoData#(Rgb888)) rgb888;
   interface Get#(VideoData#(Yyuv)) yyuv;
endinterface

(* synthesize *)
module mkRgb888ToYyuv(Rgb888ToYyuv);
    Reg#(VideoData#(Rgb888)) rgb888StageReg <- mkReg(unpack(0));
    Reg#(VideoData#(Yuv444Intermediates)) yuv444IntermediatesStageReg <- mkReg(unpack(0));
    Reg#(VideoData#(Yuv444)) yuv444StageReg <- mkReg(unpack(0));
    Reg#(VideoData#(Yyuv)) yuv422StageReg <- mkReg(unpack(0));
    Reg#(Bool) evenOddPixelReg <- mkReg(False);

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

    rule yuv444_rule;
        let previous = yuv444IntermediatesStageReg;
        yuv444StageReg <= VideoData {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
	    pixel: (previous.de != 0) ? yuvIntermediatesToYuv444(previous.pixel) : unpack(0)
        };
    endrule

    rule yuv422_rule;
        let previous = yuv444StageReg;
        if (previous.de != 0)
            evenOddPixelReg <= !evenOddPixelReg;
        Yyuv data = Yyuv { uv: evenOddPixelReg ? previous.pixel.u : previous.pixel.v,
                           yy: previous.pixel.y };
        yuv422StageReg <= VideoData {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
            pixel: data
        };
    endrule

   interface Put rgb888;
      method Action put(VideoData#(Rgb888) v);
	 rgb888StageReg <= v;
      endmethod
   endinterface
   interface Get yyuv;
      method ActionValue#(VideoData#(Yyuv)) get();
	 return yuv422StageReg;
      endmethod
   endinterface
endmodule

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

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

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

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

import Vector::*;
import Clocks::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import GetPut::*;
import SyncBits::*;
import YUV::*;

`ifdef ZC706
typedef 24 HdmiBits;
`else
typedef 16 HdmiBits;
`endif

interface HDMI#(type pixelType);
    method Bit#(1) hdmi_vsync;
    method Bit#(1) hdmi_hsync;
    method Bit#(1) hdmi_de;
    method pixelType hdmi_data;
    interface Clock hdmi_clock_if;
    interface Reset deleteme_unused_reset;
endinterface

interface HdmiInternalRequest;
    method Action setTestPattern(Bit#(1) v);
    method Action setPatternColor(Bit#(32) v);
    method Action setHsyncWidth(Bit#(12) hsyncWidth);
    method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max, Bit#(12) mid);
    method Action setVsyncWidth(Bit#(11) vsyncWidth);
    method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max, Bit#(11) mid);
    method Action setNumberOfLines(Bit#(11) lines);
    method Action setNumberOfPixels(Bit#(12) pixels);
    method Action waitForVsync(Bit#(32) unused);
endinterface
interface HdmiInternalIndication;
    method Action vsync(Bit#(64) v, Bit#(32) vs);
endinterface
interface HdmiInternalStatus;
    method Bit#(11) getNumberOfLines();
    method Bit#(12) getNumberOfPixels();
    method Bool dataEnable();
endinterface

interface HdmiGenerator#(type pixelType);
    interface HdmiInternalRequest control;
    interface HdmiInternalStatus  status;
    interface Get#(VideoData#(pixelType)) rgb888;
    interface Put#(Bit#(32)) request;
endinterface

module mkHdmiGenerator#(Clock axi_clock, Reset axi_reset,
   SyncPulseIfc vsyncPulse, HdmiInternalIndication indication)(HdmiGenerator#(Rgb888));
    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);
    Vector#(4, Reg#(Bit#(24))) patternRegs <- replicateM(mkSyncReg(24'h00FFFFFF, axi_clock, axi_reset, defaultClock));
    Reg#(Bit#(2)) patternIndex <- mkReg(0);
    Reg#(Bit#(1)) shadowTestPatternEnabled <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) testPatternEnabled <- mkReg(1);
    Reg#(Bool) waitingForVsync <- mkSyncReg(False, axi_clock, axi_reset, defaultClock);
    SyncPulseIfc vsyncCountPulse <- mkSyncHandshake(defaultClock, defaultReset, axi_clock);
    SyncPulseIfc sendVsyncIndication <- mkSyncHandshake(defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(24)) pixelData <- mkReg(24'hFF00FF);
    FIFOF#(Bit#(24)) pixelFifo <- mkLFIFOF();

    Reg#(VideoData#(Rgb888)) rgb888StageReg <- mkReg(unpack(0));
    Reg#(Bool) evenOddPixelReg <- mkReg(False);

    Reg#(Bit#(32)) underflowCount <- mkReg(0);
    Reg#(Bit#(32)) underflowCountAxi <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(32)) counter <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    Reg#(Bit#(32)) vsyncCounter <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    Reg#(Bit#(32)) elapsed <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    Reg#(Bit#(32)) elapsedVsync <- mkReg(0, clocked_by axi_clock, reset_by axi_reset);
    rule axicyclecount;
       counter <= counter + 1;
    endrule

    rule vsyncCount if (vsyncCountPulse.pulse());
       vsyncCounter <= vsyncCounter+1;
    endrule
    rule vsyncReceived if (sendVsyncIndication.pulse());
       elapsed <= counter;
       elapsedVsync <= vsyncCounter;
       indication.vsync(extend(counter - elapsed), extend(vsyncCounter - elapsedVsync));
       waitingForVsync <= False;
    endrule

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

    rule inc_counters;
        if (lineCount == 0 && pixelCount == 0) begin
	    vsyncCountPulse.send();
            vsyncPulse.send();
            if (waitingForVsync) begin
	       sendVsyncIndication.send();
	    end
            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 output_data_rule;
        let hsync = (pixelCount < hsyncWidth) ? 1 : 0;
        let vsync = (lineCount < vsyncWidth) ? 1 : 0;
        let isActiveLine = (lineCount >= deLineCountMinimum && lineCount < deLineCountMaximum);
        let dataEnable = (pixelCount >= dePixelCountMinimum && pixelCount < dePixelCountMaximum && isActiveLine);
       Rgb888 pixel = unpack(0);
       if (dataEnable) begin
	   pixel = unpack(pixelData);
       end
        rgb888StageReg <= VideoData {de: pack(dataEnable),
				     vsync: vsync, hsync: hsync, pixel: pixel };
    endrule

   rule testpattern_setup;
      patternIndex <= {pack(lineCount >= lineMidpoint), pack(pixelCount >= pixelMidpoint)};
   endrule

   rule testpattern_rule if (testPatternEnabled != 0);
      pixelData <= patternRegs[patternIndex];
   endrule

    interface Put request;
        method Action put(Bit#(32) v) if (testPatternEnabled == 0);
	   pixelData <= v[23:0];
        endmethod
    endinterface: request

    interface HdmiInternalStatus status;
	method Bit#(11) getNumberOfLines();
	   return numberOfLines;
	endmethod
	method Bit#(12) getNumberOfPixels();
	   return numberOfPixels;
	endmethod
   method Bool dataEnable();
        let isActiveLine = (lineCount >= deLineCountMinimum && lineCount < deLineCountMaximum);
      return (pixelCount >= dePixelCountMinimum && pixelCount < dePixelCountMaximum && isActiveLine);
   endmethod

    endinterface
    interface HdmiInternalRequest control;
        method Action setPatternColor(Bit#(32) v);
            patternRegs[0] <= v[23:0];
        endmethod
        method Action setTestPattern(Bit#(1) v);
            shadowTestPatternEnabled <= v;
        endmethod
        method Action setHsyncWidth(Bit#(12) width);
            hsyncWidth <= width;
        endmethod
        method Action setDePixelCountMinMax(Bit#(12) min, Bit#(12) max, Bit#(12) mid);
            dePixelCountMinimum <= min;
            dePixelCountMaximum <= max;
            pixelMidpoint <= mid;
        endmethod
        method Action setVsyncWidth(Bit#(11) width);
            vsyncWidth <= width;
        endmethod
        method Action setDeLineCountMinMax(Bit#(11) min, Bit#(11) max, Bit#(11) mid);
            deLineCountMinimum <= min;
            deLineCountMaximum <= max;
            lineMidpoint <= mid;
        endmethod
        method Action setNumberOfLines(Bit#(11) lines);
            numberOfLines <= lines;
        endmethod
        method Action setNumberOfPixels(Bit#(12) pixels);
            numberOfPixels <= pixels;
        endmethod
        method Action waitForVsync(Bit#(32) unused);
            waitingForVsync <= True;
        endmethod
    endinterface
   interface Get rgb888;
      method ActionValue#(VideoData#(Rgb888)) get();
	 return rgb888StageReg;
      endmethod
   endinterface
endmodule

module mkHDMI#(Get#(VideoData#(pixelType)) videoInput)(HDMI#(Bit#(pixelsz)))
   provisos (Bits#(VideoData#(pixelType), a__), Bits#(pixelType,pixelsz));
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   Wire#(VideoData#(pixelType)) video <- mkDWire(unpack(0));
   rule getvideo;
      let v <- videoInput.get();
      video <= v;
   endrule

   method Bit#(1) hdmi_vsync;
      return video.vsync;
   endmethod
   method Bit#(1) hdmi_hsync;
      return video.hsync;
   endmethod
   method Bit#(1) hdmi_de;
      return video.de;
   endmethod
   method Bit#(pixelsz) hdmi_data;
      return pack(video.pixel);
   endmethod
   interface hdmi_clock_if = defaultClock;
   interface deleteme_unused_reset = defaultReset;
endmodule

interface Rgb888ToYyuv;
   interface Put#(VideoData#(Rgb888)) rgb888;
   interface Get#(VideoData#(Yyuv)) yyuv;
endinterface

(* synthesize *)
module mkRgb888ToYyuv(Rgb888ToYyuv);
    Reg#(VideoData#(Rgb888)) rgb888StageReg <- mkReg(unpack(0));
    Reg#(VideoData#(Yuv444Intermediates)) yuv444IntermediatesStageReg <- mkReg(unpack(0));
    Reg#(VideoData#(Yuv444)) yuv444StageReg <- mkReg(unpack(0));
    Reg#(VideoData#(Yyuv)) yuv422StageReg <- mkReg(unpack(0));
    Reg#(Bool) evenOddPixelReg <- mkReg(False);

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

    rule yuv444_rule;
        let previous = yuv444IntermediatesStageReg;
        yuv444StageReg <= VideoData {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
	    pixel: (previous.de != 0) ? yuvIntermediatesToYuv444(previous.pixel) : unpack(0)
        };
    endrule

    rule yuv422_rule;
        let previous = yuv444StageReg;
        if (previous.de != 0)
            evenOddPixelReg <= !evenOddPixelReg;
        Yyuv data = Yyuv { uv: evenOddPixelReg ? previous.pixel.u : previous.pixel.v,
                           yy: previous.pixel.y };
        yuv422StageReg <= VideoData {
            vsync: previous.vsync, hsync: previous.hsync, de: previous.de,
            pixel: data
        };
    endrule

   interface Put rgb888;
      method Action put(VideoData#(Rgb888) v);
	 rgb888StageReg <= v;
      endmethod
   endinterface
   interface Get yyuv;
      method ActionValue#(VideoData#(Yyuv)) get();
	 return yuv422StageReg;
      endmethod
   endinterface
endmodule


changing mkUnFunnel1PipesPipelined such that it doesn't rely on dead-code to remove unused fifo instantiations.  I don't think this is a problem but I was interested to see how it could be done

// 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 FIFOF::*;
import GetPut::*;
import Connectable::*;
import Vector::*;
import MIMO::*;
import DefaultValue::*;

interface PipeIn#(type a);
   method Action enq(a v);
   method Bool notFull();
endinterface

interface PipeOut#(type a);
   method a first();
   method Action deq();
   method Bool notEmpty();
endinterface

typeclass ToPipeIn#(type a, type b);
   function PipeIn#(a) toPipeIn(b in);
endtypeclass

typeclass ToPipeOut#(type a, type b);
   function PipeOut#(a) toPipeOut(b in);
endtypeclass

typeclass MkPipeOut#(type a, type b);
   module mkPipeOut#(b in)(PipeOut#(a));
endtypeclass

instance ToPipeIn#(a, FIFOF#(a));
   function PipeIn#(a) toPipeIn(FIFOF#(a) in);
      return (interface PipeIn#(a);
		 method enq = in.enq;
		 method notFull = in.notFull;
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(a, Reg#(a));
   function PipeOut#(a) toPipeOut(Reg#(a) in);
      return (interface PipeOut#(a);
		 method first(); return in; endmethod
		 method Action deq(); endmethod
		 method Bool notEmpty(); return False; endmethod
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(a, FIFOF#(a));
   function PipeOut#(a) toPipeOut(FIFOF#(a) in);
      return (interface PipeOut#(a);
		 method first = in.first;
		 method deq = in.deq;
		 method notEmpty = in.notEmpty;
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(Vector#(n,a), MIMO#(k,n,sz,a));
   function PipeOut#(Vector#(n,a)) toPipeOut(MIMO#(k,n,sz,a) in);
      return (interface PipeOut#(a);
		 method first = in.first;
		 method Action deq() if (in.deqReadyN(fromInteger(valueOf(n))));
		    in.deq(fromInteger(valueOf(n)));
		 endmethod
		 method Bool notEmpty();
		    return in.deqReadyN(fromInteger(valueOf(n)));
		 endmethod
	      endinterface);
   endfunction
endinstance

instance MkPipeOut#(a, Get#(a))
   provisos (Bits#(a, asz));
   module mkPipeOut#(Get#(a) in)(PipeOut#(a));
      FIFOF#(a) fifo <- mkFIFOF();
      rule connect;
	 let v <- in.get();
	 fifo.enq(v);
      endrule
      return toPipeOut(fifo);
   endmodule
endinstance

instance ToGet #(PipeOut #(a), a);
   function Get #(a) toGet (PipeOut #(a) po);
      return (interface Get;
                 method ActionValue #(a) get ();
                    po.deq ();
                    return po.first ();
                 endmethod
              endinterface);
   endfunction
endinstance

instance Connectable#(PipeOut#(a),Put#(a));
   module mkConnection#(PipeOut#(a) in, Put#(a) out)(Empty);
      rule connect;
	 let v = in.first;
	 in.deq();
	 out.put(v);
      endrule
   endmodule
endinstance

function PipeOut#(a) unvectorPipeOut(PipeOut#(Vector#(1,a)) in);
   return (interface PipeOut#(a);
	      method first = in.first[0];
	      method deq = in.deq;
	      method notEmpty = in.notEmpty;
	   endinterface);
endfunction

function PipeOut#(Tuple2#(a,b)) zipPipeOut(PipeOut#(a) ina, PipeOut#(b) inb);
      return (interface PipeOut#(Tuple2#(a,b));
		 method Tuple2#(a,b) first(); return tuple2(ina.first, inb.first); endmethod
		 method Action deq(); ina.deq(); inb.deq(); endmethod
		 method Bool notEmpty(); return ina.notEmpty() && inb.notEmpty(); endmethod
	      endinterface);
   endfunction

module mkFunnel#(PipeOut#(Vector#(mk,a)) in)(PipeOut#(Vector#(m, a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Add#(a__, TMul#(asz, m), TMul#(asz, mk)),
	     Add#(1, b__, asz),
	     Add#(2, c__, mk),
	     Add#(d__, m, mk),
	     Add#(asz, m, e__),
	     Add#(asz, mk, f__));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   MIMOConfiguration cfg = defaultValue();
   MIMO#(mk, m, mk, a) mimo <- mkMIMO(cfg);
   rule consumer if (mimo.enqReadyN(mk));
      Vector#(mk, a) v = in.first();
      in.deq();
      mimo.enq(mk, v);
   endrule

   method Vector#(m, a) first() if (mimo.deqReadyN(m));
      return mimo.first();
   endmethod
   method Action deq() if (mimo.deqReadyN(m));
      mimo.deq(m);
   endmethod
   method notEmpty();
      return mimo.deqReadyN(m);
   endmethod
endmodule

module mkFunnel1#(PipeOut#(Vector#(k,a)) in)(PipeOut#(a))
   provisos (Bits#(a, asz), Log#(k,ksz));

   Reg#(Bit#(ksz)) selector <- mkReg(0);

   method a first();
      return in.first[selector];
   endmethod
   method Action deq();
      if (selector == fromInteger(valueOf(k)-1)) begin
	 in.deq();
	 selector <= 0;
      end
      else
	 selector <= selector + 1;
   endmethod
   method notEmpty();
      return in.notEmpty();
   endmethod
endmodule

typedef Vector#(k,PipeOut#(a)) FunnelPipe#(numeric type k, type a, numeric type bpc);

module mkFunnel1PipesPipelined#(Vector#(k,PipeOut#(a)) in) (FunnelPipe#(1,a,bpc))
   provisos (Log#(k, logk),
	     Bits#(a,a__),
	     Div#(logk,bpc,stages));
   // this relies on the fact that dead-code will remove unused fifo instantiations (see foo in mkUnFunnel1PipesPipelined)
   Vector#(stages, Vector#(k, FIFOF#(a))) buffs  <- replicateM(replicateM(mkFIFOF));
   Vector#(TAdd#(stages,1), Vector#(k, PipeOut#(a))) infss = append(map(map(toPipeOut),buffs), cons(in,nil));
   for(Integer j = valueOf(stages); j > 0; j=j-1)
      for(Integer i = 0; i < 2**(j*valueOf(bpc)) && i < valueOf(k); i=i+1)
	 rule xfer;
	    let x <- toGet(infss[j][i]).get;
	    buffs[j-1][i/(2**valueOf(bpc))].enq(x);
	 endrule
   return cons(infss[0][0],nil);
endmodule

module mkUnFunnel1PipesPipelined#(PipeOut#(Tuple2#(Bit#(TLog#(k)),a)) in) (FunnelPipe#(k,a,bpc))
   provisos (Log#(k, logk),
	     Bits#(a,a__),
	     Add#(1,b__,k),
	     Div#(logk,bpc,stages));
   // the only reason to have foo is if you don't believe that dead-code will remove unused fifo instantiations
   module foo#(Integer i) (Vector#(k, FIFOF#(Tuple2#(Bit#(logk),a))));
      Vector#(k, FIFOF#(Tuple2#(Bit#(logk),a))) rv;
      for(Integer j = 0; j < 2**((i+1)*valueOf(bpc)) && j < valueOf(k); j=j+1)
	 rv[j] <- mkFIFOF;
      return rv;
   endmodule
   Vector#(stages, Vector#(k, FIFOF#(Tuple2#(Bit#(logk),a)))) buffs  <- genWithM(foo);
   Vector#(TAdd#(stages,1), Vector#(k, PipeOut#(Tuple2#(Bit#(logk),a)))) infss = cons(cons(in,replicate(?)), map(map(toPipeOut),buffs));
   for(Integer j = 0; j < valueOf(stages); j=j+1)
      for(Integer i = 0; i < 2**(j*valueOf(bpc)); i=i+1)
	 rule xfer;
	    match{.idx, .v} <- toGet(infss[j][i]).get;
	    Integer bits = (j == valueOf(stages)-1) ? valueOf(logk)-(j*valueOf(bpc)) : valueOf(bpc);
	    Integer sh = valueOf(bpc)-bits;
	    for(Integer l = 0; l < 2**bits; l=l+1) begin
	       Bit#(bpc) x = fromInteger(l)<<fromInteger(sh);
	       if(idx[(valueOf(logk)-1):(valueOf(logk)-valueOf(bpc))] == x)
		  buffs[j][(2**bits)*i+l].enq(tuple2(idx<<valueOf(bpc), v));
	    end
	 endrule
   function PipeOut#(a) payload(PipeOut#(Tuple2#(Bit#(logk),a)) x) =
      (interface PipeOut;
	  method a first;
	     return tpl_2(x.first);
	  endmethod
	  method Action deq = x.deq;
	  method Bool notEmpty = x.notEmpty;
       endinterface);
   return map(payload,infss[valueOf(stages)]);
endmodule

module mkUnfunnel#(PipeOut#(Vector#(m,a)) in)(PipeOut#(Vector#(mk, a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Add#(1, b__, asz),
	     Add#(2, c__, mk),
	     Add#(d__, m, mk),
	     Add#(asz, m, e__),
	     Add#(asz, mk, f__));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   MIMOConfiguration cfg = defaultValue();
   MIMO#(m, mk, mk, a) mimo <- mkMIMO(cfg);
   rule consumer if (mimo.enqReadyN(m));
      Vector#(m, a) v = in.first();
      in.deq();
      mimo.enq(m, v);
   endrule

   method Vector#(mk, a) first() if (mimo.deqReadyN(mk));
      return mimo.first();
   endmethod
   method Action deq() if (mimo.deqReadyN(mk));
      mimo.deq(mk);
   endmethod
   method notEmpty();
      return mimo.deqReadyN(mk);
   endmethod
endmodule

module mkFunnelPipes#(Vector#(mk, PipeOut#(a)) ins)(Vector#(m, PipeOut#(a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Log#(k,ksz)
      );
   let k = fromInteger(valueOf(k));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   Vector#(m, FIFOF#(a)) fifos <- replicateM(mkFIFOF);
   for (Integer i = 0; i < m; i = i+1) begin
      Reg#(Bit#(asz)) which <- mkReg(0);
      rule consumer;
	 let index = (which << valueOf(ksz)) + fromInteger(i);
	 let v <- toGet(ins[index]).get();
	 fifos[i].enq(v);
	 which <= (which + 1) % k;
      endrule
   end

   return map(toPipeOut, fifos);
endmodule

module mkFunnelPipes1#(Vector#(k, PipeOut#(a)) ins)(PipeOut#(a))
   provisos (Bits#(a, asz),
	     Log#(k,ksz)
      );
   let k = fromInteger(valueOf(k));

   Reg#(Bit#(ksz)) selector <- mkReg(0);

   method a first();
      return ins[selector].first();
   endmethod
   method Action deq();
      ins[selector].deq();
      if (selector == fromInteger(valueOf(k)-1))
	 selector <= 0;
   else
      selector <= selector + 1;
   endmethod
   method Bool notEmpty();
      return ins[selector].notEmpty();
   endmethod
endmodule

module mkUnfunnelPipes#(Vector#(m, PipeOut#(a)) ins)(Vector#(mk, PipeOut#(a)))
   provisos (Mul#(m, k, mk),
	     Log#(k,ksz),
	     Bits#(a, asz),
	     Add#(1, b__, asz)
	     );
   let m = fromInteger(valueOf(m));
   let k = fromInteger(valueOf(k));
   let mk = fromInteger(valueOf(mk));

   Vector#(mk, FIFOF#(a)) fifos <- replicateM(mkFIFOF);
   for (Integer i = 0; i < m; i = i + 1) begin
      Reg#(Bit#(asz)) which <- mkReg(0);
      rule consumer;
	 let index = (which << valueOf(ksz)) + fromInteger(i);
	 let v <- toGet(ins[i]).get();
	 fifos[index].enq(v);
	 which <= (which + 1) % k;
      endrule
   end
   return map(toPipeOut, fifos);
endmodule

module mkRepeat#(UInt#(n) repetitions, PipeOut#(a) inpipe)(PipeOut#(a));
   Reg#(UInt#(n)) count <- mkReg(0);
   method first = inpipe.first;
   method Action deq();
      let c = count + 1;
      if (count == (repetitions - 1)) begin
	 c = 0;
	 inpipe.deq();
      end
      count <= c;
   endmethod
   method notEmpty = inpipe.notEmpty;
endmodule

module mkForkVector#(PipeOut#(a) inpipe)(Vector#(n, PipeOut#(a)))
   provisos (Bits#(a, asz));
   Vector#(n, FIFOF#(a)) fifos <- replicateM(mkFIFOF());
   rule forkelts;
      let v = inpipe.first();
      inpipe.deq;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 fifos[i].enq(v);
      end
   endrule
   return map(toPipeOut, fifos);
endmodule

module mkSizedForkVector#(Integer size, PipeOut#(a) inpipe)(Vector#(n, PipeOut#(a)))
   provisos (Bits#(a, asz));
   Vector#(n, FIFOF#(a)) fifos <- replicateM(mkSizedFIFOF(size));
   rule forkelts;
      let v = inpipe.first();
      inpipe.deq;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 fifos[i].enq(v);
      end
   endrule
   return map(toPipeOut, fifos);
endmodule

module mkJoin#(function c f(a av, b bv), PipeOut#(a) apipe, PipeOut#(b) bpipe)(PipeOut#(c));
   method c first();
      let av = apipe.first();
      let bv = bpipe.first();
      return f(av, bv);
   endmethod
   method Action deq();
      apipe.deq();
      bpipe.deq();
   endmethod
   method Bool notEmpty();
      return apipe.notEmpty() && bpipe.notEmpty();
   endmethod
endmodule

module mkJoinVector#(function b f(Vector#(n, a) av), Vector#(n, PipeOut#(a)) apipes)(PipeOut#(b))
   provisos (Bits#(Vector#(n,a),vasz));
   method b first();
      function a getfirst(PipeOut#(a) pipein); return pipein.first(); endfunction
      Vector#(n,a) vec = map(getfirst, apipes);
      return f(vec);
   endmethod
   method Action deq();
      function a getfirst(PipeOut#(a) pipein); return pipein.first(); endfunction
      for (Integer i = 0; i < valueOf(n); i = i + 1)
	 apipes[i].deq();
   endmethod
   method Bool notEmpty();
      function Bool getNotEmpty(PipeOut#(a) pipein); return pipein.notEmpty(); endfunction
      function Bool myand(Bool a, Bool b); return a && b; endfunction
      return foldl(myand, True, map(getNotEmpty, apipes));
   endmethod
endmodule

function PipeOut#(b) mapPipe(function b f(a av), PipeOut#(a) apipe);
   return (interface PipeOut#(b);
      method b first();
	 let av = apipe.first();
	 return f(av);
      endmethod
      method Action deq();
	 apipe.deq();
      endmethod
      method Bool notEmpty();
	 return apipe.notEmpty();
      endmethod
      endinterface);
endfunction

// buffered version of mapPipe
module mkMap#(function b f(a av), PipeOut#(a) apipe)(PipeOut#(b))
   provisos (Bits#(b,bsz));
   FIFOF#(b) fifo <- mkFIFOF();
   rule compute;
      let v <- toGet(apipe).get();
      fifo.enq(f(v));
   endrule
   return toPipeOut(fifo);
endmodule

typedef (function Module #(PipeOut #(tb)) mkPipeOut(PipeOut#(ta) ifc)) PipeOutConstructor#(type ta, type tb);

typeclass ReducePipe#( numeric type n, type a);
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(n,a)) inpipe,
				 PipeOut#(a) ifc);
   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(n,PipeOut#(a)) inpipe,
				  PipeOut#(a) ifc);
endtypeclass
instance ReducePipe#(1, a);
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(1,a)) inpipe,
				 PipeOut#(a) ifc);
      let pipe = mapPipe(head, inpipe);
      return pipe;
   endmodule
   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(1,PipeOut#(a)) inpipes,
				  PipeOut#(a) ifc);
      return inpipes[0];
   endmodule
endinstance
instance ReducePipe#(2, a);
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(2,a)) inpipe,
				 PipeOut#(a) ifc);
      function Tuple2#(a,a) foo(Vector#(2,a) invec); return tuple2(invec[0], invec[1]); endfunction
      PipeOut#(Tuple2#(a,a)) zippipe = mapPipe(foo, inpipe);
      let pipe <- combinepipe(zippipe);
      return pipe;
   endmodule
   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(2,PipeOut#(a)) inpipes,
				  PipeOut#(a) ifc);
      let pipe <- combinepipe(zipPipeOut(inpipes[0], inpipes[1]));
      return pipe;
   endmodule
endinstance

instance ReducePipe#(n, a)
   provisos (Add#(TDiv#(n,2), a__, n),
	     Bits#(Vector#(TDiv#(n,2), a), b__),
	     ReducePipe#(TDiv#(n,2),a));
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(n,a)) inpipe,
				 PipeOut#(a) ifc);
      FIFOF#(Vector#(TDiv#(n,2),a)) infifo0 <- mkFIFOF;
      FIFOF#(Vector#(TDiv#(n,2),a)) infifo1 <- mkFIFOF;
      rule splitinput;
	 let v = inpipe.first();
	 inpipe.deq();
	 infifo0.enq(takeAt(0, v));
	 infifo1.enq(takeAt(valueOf(TDiv#(n,2)), v));
      endrule
      PipeOut#(Vector#(TDiv#(n,2),a)) inpipe0 = toPipeOut(infifo0);
      PipeOut#(Vector#(TDiv#(n,2),a)) inpipe1 = toPipeOut(infifo1);

      PipeOut#(a) p0 <- mkReducePipe(combinepipe, inpipe0);
      PipeOut#(a) p1 <- mkReducePipe(combinepipe, inpipe1);

      PipeOut#(a) outpipe <- combinepipe(zipPipeOut(p0, p1));
      return outpipe;
   endmodule

   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(n, PipeOut#(a)) inpipes,
				 PipeOut#(a) ifc);
      Vector#(TDiv#(n,2),PipeOut#(a)) pipes0 = takeAt(0, inpipes);
      Vector#(TDiv#(n,2),PipeOut#(a)) pipes1 = takeAt(valueOf(TDiv#(n,2)), inpipes);

      PipeOut#(a) p0 <- mkReducePipes(combinepipe, pipes0);
      PipeOut#(a) p1 <- mkReducePipes(combinepipe, pipes1);

      PipeOut#(a) outpipe <- combinepipe(zipPipeOut(p0, p1));
      return outpipe;
   endmodule
endinstance

interface FirstLastPipe#(type a);
   interface PipeOut#(Tuple2#(Bool,Bool)) pipe;
   method Action start(a count);
endinterface

module mkFirstLastPipe(FirstLastPipe#(a))
   provisos (Bits#(a,asz), Ord#(a), Arith#(a), Eq#(a));
   Reg#(a) countReg <- mkReg(0);
   Reg#(Bool) firstReg <- mkReg(False);
   Reg#(Bool) lastReg <- mkReg(False);
   interface PipeOut pipe;
      method Tuple2#(Bool, Bool) first();
	 return tuple2(firstReg, lastReg);
      endmethod
      method Action deq() if (countReg > 0);
	 firstReg <= False;
	 let c = countReg - 1;
	 if (c == 1)
	    lastReg <= True;
	 countReg <= c;
      endmethod
      method Bool notEmpty();
	 return countReg > 0;
      endmethod
   endinterface
   method Action start(a count) if (countReg == 0);
      firstReg <= True;
      lastReg <= False;
      countReg <= count;
   endmethod
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 FIFOF::*;
import GetPut::*;
import Connectable::*;
import Vector::*;
import MIMO::*;
import DefaultValue::*;

interface PipeIn#(type a);
   method Action enq(a v);
   method Bool notFull();
endinterface

interface PipeOut#(type a);
   method a first();
   method Action deq();
   method Bool notEmpty();
endinterface

typeclass ToPipeIn#(type a, type b);
   function PipeIn#(a) toPipeIn(b in);
endtypeclass

typeclass ToPipeOut#(type a, type b);
   function PipeOut#(a) toPipeOut(b in);
endtypeclass

typeclass MkPipeOut#(type a, type b);
   module mkPipeOut#(b in)(PipeOut#(a));
endtypeclass

instance ToPipeIn#(a, FIFOF#(a));
   function PipeIn#(a) toPipeIn(FIFOF#(a) in);
      return (interface PipeIn#(a);
		 method enq = in.enq;
		 method notFull = in.notFull;
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(a, Reg#(a));
   function PipeOut#(a) toPipeOut(Reg#(a) in);
      return (interface PipeOut#(a);
		 method first(); return in; endmethod
		 method Action deq(); endmethod
		 method Bool notEmpty(); return False; endmethod
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(a, FIFOF#(a));
   function PipeOut#(a) toPipeOut(FIFOF#(a) in);
      return (interface PipeOut#(a);
		 method first = in.first;
		 method deq = in.deq;
		 method notEmpty = in.notEmpty;
	      endinterface);
   endfunction
endinstance

instance ToPipeOut#(Vector#(n,a), MIMO#(k,n,sz,a));
   function PipeOut#(Vector#(n,a)) toPipeOut(MIMO#(k,n,sz,a) in);
      return (interface PipeOut#(a);
		 method first = in.first;
		 method Action deq() if (in.deqReadyN(fromInteger(valueOf(n))));
		    in.deq(fromInteger(valueOf(n)));
		 endmethod
		 method Bool notEmpty();
		    return in.deqReadyN(fromInteger(valueOf(n)));
		 endmethod
	      endinterface);
   endfunction
endinstance

instance MkPipeOut#(a, Get#(a))
   provisos (Bits#(a, asz));
   module mkPipeOut#(Get#(a) in)(PipeOut#(a));
      FIFOF#(a) fifo <- mkFIFOF();
      rule connect;
	 let v <- in.get();
	 fifo.enq(v);
      endrule
      return toPipeOut(fifo);
   endmodule
endinstance

instance ToGet #(PipeOut #(a), a);
   function Get #(a) toGet (PipeOut #(a) po);
      return (interface Get;
                 method ActionValue #(a) get ();
                    po.deq ();
                    return po.first ();
                 endmethod
              endinterface);
   endfunction
endinstance

instance Connectable#(PipeOut#(a),Put#(a));
   module mkConnection#(PipeOut#(a) in, Put#(a) out)(Empty);
      rule connect;
	 let v = in.first;
	 in.deq();
	 out.put(v);
      endrule
   endmodule
endinstance

function PipeOut#(a) unvectorPipeOut(PipeOut#(Vector#(1,a)) in);
   return (interface PipeOut#(a);
	      method first = in.first[0];
	      method deq = in.deq;
	      method notEmpty = in.notEmpty;
	   endinterface);
endfunction

function PipeOut#(Tuple2#(a,b)) zipPipeOut(PipeOut#(a) ina, PipeOut#(b) inb);
      return (interface PipeOut#(Tuple2#(a,b));
		 method Tuple2#(a,b) first(); return tuple2(ina.first, inb.first); endmethod
		 method Action deq(); ina.deq(); inb.deq(); endmethod
		 method Bool notEmpty(); return ina.notEmpty() && inb.notEmpty(); endmethod
	      endinterface);
   endfunction

module mkFunnel#(PipeOut#(Vector#(mk,a)) in)(PipeOut#(Vector#(m, a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Add#(a__, TMul#(asz, m), TMul#(asz, mk)),
	     Add#(1, b__, asz),
	     Add#(2, c__, mk),
	     Add#(d__, m, mk),
	     Add#(asz, m, e__),
	     Add#(asz, mk, f__));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   MIMOConfiguration cfg = defaultValue();
   MIMO#(mk, m, mk, a) mimo <- mkMIMO(cfg);
   rule consumer if (mimo.enqReadyN(mk));
      Vector#(mk, a) v = in.first();
      in.deq();
      mimo.enq(mk, v);
   endrule

   method Vector#(m, a) first() if (mimo.deqReadyN(m));
      return mimo.first();
   endmethod
   method Action deq() if (mimo.deqReadyN(m));
      mimo.deq(m);
   endmethod
   method notEmpty();
      return mimo.deqReadyN(m);
   endmethod
endmodule

module mkFunnel1#(PipeOut#(Vector#(k,a)) in)(PipeOut#(a))
   provisos (Bits#(a, asz), Log#(k,ksz));

   Reg#(Bit#(ksz)) selector <- mkReg(0);

   method a first();
      return in.first[selector];
   endmethod
   method Action deq();
      if (selector == fromInteger(valueOf(k)-1)) begin
	 in.deq();
	 selector <= 0;
      end
      else
	 selector <= selector + 1;
   endmethod
   method notEmpty();
      return in.notEmpty();
   endmethod
endmodule

typedef Vector#(k,PipeOut#(a)) FunnelPipe#(numeric type k, type a, numeric type bpc);

module mkFunnel1PipesPipelined#(Vector#(k,PipeOut#(a)) in) (FunnelPipe#(1,a,bpc))
   provisos (Log#(k, logk),
	     Bits#(a,a__),
	     Div#(logk,bpc,stages));
   Vector#(stages, Vector#(k, FIFOF#(a))) buffs  <- replicateM(replicateM(mkFIFOF));
   Vector#(TAdd#(stages,1), Vector#(k, PipeOut#(a))) infss = append(map(map(toPipeOut),buffs), cons(in,nil));
   for(Integer j = valueOf(stages); j > 0; j=j-1)
      for(Integer i = 0; i < 2**(j*valueOf(bpc)) && i < valueOf(k); i=i+1)
	 rule xfer;
	    let x <- toGet(infss[j][i]).get;
	    buffs[j-1][i/(2**valueOf(bpc))].enq(x);
	 endrule
   return cons(infss[0][0],nil);
endmodule

module mkUnFunnel1PipesPipelined#(PipeOut#(Tuple2#(Bit#(TLog#(k)),a)) in) (FunnelPipe#(k,a,bpc))
   provisos (Log#(k, logk),
	     Bits#(a,a__),
	     Add#(1,b__,k),
	     Div#(logk,bpc,stages));
   Vector#(stages, Vector#(k, FIFOF#(Tuple2#(Bit#(logk),a)))) buffs  <- replicateM(replicateM(mkFIFOF));
   Vector#(TAdd#(stages,1), Vector#(k, PipeOut#(Tuple2#(Bit#(logk),a)))) infss = cons(cons(in,replicate(?)), map(map(toPipeOut),buffs));
   for(Integer j = 0; j < valueOf(stages); j=j+1)
      for(Integer i = 0; i < 2**(j*valueOf(bpc)); i=i+1)
	 rule xfer;
	    match{.idx, .v} <- toGet(infss[j][i]).get;
	    Integer bits = (j == valueOf(stages)-1) ? valueOf(logk)-(j*valueOf(bpc)) : valueOf(bpc);
	    Integer sh = valueOf(bpc)-bits;
	    for(Integer l = 0; l < 2**bits; l=l+1) begin
	       Bit#(bpc) x = fromInteger(l)<<fromInteger(sh);
	       if(idx[(valueOf(logk)-1):(valueOf(logk)-valueOf(bpc))] == x)
		  buffs[j][(2**bits)*i+l].enq(tuple2(idx<<valueOf(bpc), v));
	    end
	 endrule
   function PipeOut#(a) payload(PipeOut#(Tuple2#(Bit#(logk),a)) x) =
      (interface PipeOut;
	  method a first;
	     return tpl_2(x.first);
	  endmethod
	  method Action deq = x.deq;
	  method Bool notEmpty = x.notEmpty;
       endinterface);
   return map(payload,infss[valueOf(stages)]);
endmodule

module mkUnfunnel#(PipeOut#(Vector#(m,a)) in)(PipeOut#(Vector#(mk, a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Add#(1, b__, asz),
	     Add#(2, c__, mk),
	     Add#(d__, m, mk),
	     Add#(asz, m, e__),
	     Add#(asz, mk, f__));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   MIMOConfiguration cfg = defaultValue();
   MIMO#(m, mk, mk, a) mimo <- mkMIMO(cfg);
   rule consumer if (mimo.enqReadyN(m));
      Vector#(m, a) v = in.first();
      in.deq();
      mimo.enq(m, v);
   endrule

   method Vector#(mk, a) first() if (mimo.deqReadyN(mk));
      return mimo.first();
   endmethod
   method Action deq() if (mimo.deqReadyN(mk));
      mimo.deq(mk);
   endmethod
   method notEmpty();
      return mimo.deqReadyN(mk);
   endmethod
endmodule

module mkFunnelPipes#(Vector#(mk, PipeOut#(a)) ins)(Vector#(m, PipeOut#(a)))
   provisos (Mul#(m, k, mk),
	     Bits#(a, asz),
	     Log#(k,ksz)
      );
   let k = fromInteger(valueOf(k));
   let m = fromInteger(valueOf(m));
   let mk = fromInteger(valueOf(mk));

   Vector#(m, FIFOF#(a)) fifos <- replicateM(mkFIFOF);
   for (Integer i = 0; i < m; i = i+1) begin
      Reg#(Bit#(asz)) which <- mkReg(0);
      rule consumer;
	 let index = (which << valueOf(ksz)) + fromInteger(i);
	 let v <- toGet(ins[index]).get();
	 fifos[i].enq(v);
	 which <= (which + 1) % k;
      endrule
   end

   return map(toPipeOut, fifos);
endmodule

module mkFunnelPipes1#(Vector#(k, PipeOut#(a)) ins)(PipeOut#(a))
   provisos (Bits#(a, asz),
	     Log#(k,ksz)
      );
   let k = fromInteger(valueOf(k));

   Reg#(Bit#(ksz)) selector <- mkReg(0);

   method a first();
      return ins[selector].first();
   endmethod
   method Action deq();
      ins[selector].deq();
      if (selector == fromInteger(valueOf(k)-1))
	 selector <= 0;
   else
      selector <= selector + 1;
   endmethod
   method Bool notEmpty();
      return ins[selector].notEmpty();
   endmethod
endmodule

module mkUnfunnelPipes#(Vector#(m, PipeOut#(a)) ins)(Vector#(mk, PipeOut#(a)))
   provisos (Mul#(m, k, mk),
	     Log#(k,ksz),
	     Bits#(a, asz),
	     Add#(1, b__, asz)
	     );
   let m = fromInteger(valueOf(m));
   let k = fromInteger(valueOf(k));
   let mk = fromInteger(valueOf(mk));

   Vector#(mk, FIFOF#(a)) fifos <- replicateM(mkFIFOF);
   for (Integer i = 0; i < m; i = i + 1) begin
      Reg#(Bit#(asz)) which <- mkReg(0);
      rule consumer;
	 let index = (which << valueOf(ksz)) + fromInteger(i);
	 let v <- toGet(ins[i]).get();
	 fifos[index].enq(v);
	 which <= (which + 1) % k;
      endrule
   end
   return map(toPipeOut, fifos);
endmodule

module mkRepeat#(UInt#(n) repetitions, PipeOut#(a) inpipe)(PipeOut#(a));
   Reg#(UInt#(n)) count <- mkReg(0);
   method first = inpipe.first;
   method Action deq();
      let c = count + 1;
      if (count == (repetitions - 1)) begin
	 c = 0;
	 inpipe.deq();
      end
      count <= c;
   endmethod
   method notEmpty = inpipe.notEmpty;
endmodule

module mkForkVector#(PipeOut#(a) inpipe)(Vector#(n, PipeOut#(a)))
   provisos (Bits#(a, asz));
   Vector#(n, FIFOF#(a)) fifos <- replicateM(mkFIFOF());
   rule forkelts;
      let v = inpipe.first();
      inpipe.deq;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 fifos[i].enq(v);
      end
   endrule
   return map(toPipeOut, fifos);
endmodule

module mkSizedForkVector#(Integer size, PipeOut#(a) inpipe)(Vector#(n, PipeOut#(a)))
   provisos (Bits#(a, asz));
   Vector#(n, FIFOF#(a)) fifos <- replicateM(mkSizedFIFOF(size));
   rule forkelts;
      let v = inpipe.first();
      inpipe.deq;
      for (Integer i = 0; i < valueOf(n); i = i + 1) begin
	 fifos[i].enq(v);
      end
   endrule
   return map(toPipeOut, fifos);
endmodule

module mkJoin#(function c f(a av, b bv), PipeOut#(a) apipe, PipeOut#(b) bpipe)(PipeOut#(c));
   method c first();
      let av = apipe.first();
      let bv = bpipe.first();
      return f(av, bv);
   endmethod
   method Action deq();
      apipe.deq();
      bpipe.deq();
   endmethod
   method Bool notEmpty();
      return apipe.notEmpty() && bpipe.notEmpty();
   endmethod
endmodule

module mkJoinVector#(function b f(Vector#(n, a) av), Vector#(n, PipeOut#(a)) apipes)(PipeOut#(b))
   provisos (Bits#(Vector#(n,a),vasz));
   method b first();
      function a getfirst(PipeOut#(a) pipein); return pipein.first(); endfunction
      Vector#(n,a) vec = map(getfirst, apipes);
      return f(vec);
   endmethod
   method Action deq();
      function a getfirst(PipeOut#(a) pipein); return pipein.first(); endfunction
      for (Integer i = 0; i < valueOf(n); i = i + 1)
	 apipes[i].deq();
   endmethod
   method Bool notEmpty();
      function Bool getNotEmpty(PipeOut#(a) pipein); return pipein.notEmpty(); endfunction
      function Bool myand(Bool a, Bool b); return a && b; endfunction
      return foldl(myand, True, map(getNotEmpty, apipes));
   endmethod
endmodule

function PipeOut#(b) mapPipe(function b f(a av), PipeOut#(a) apipe);
   return (interface PipeOut#(b);
      method b first();
	 let av = apipe.first();
	 return f(av);
      endmethod
      method Action deq();
	 apipe.deq();
      endmethod
      method Bool notEmpty();
	 return apipe.notEmpty();
      endmethod
      endinterface);
endfunction

// buffered version of mapPipe
module mkMap#(function b f(a av), PipeOut#(a) apipe)(PipeOut#(b))
   provisos (Bits#(b,bsz));
   FIFOF#(b) fifo <- mkFIFOF();
   rule compute;
      let v <- toGet(apipe).get();
      fifo.enq(f(v));
   endrule
   return toPipeOut(fifo);
endmodule

typedef (function Module #(PipeOut #(tb)) mkPipeOut(PipeOut#(ta) ifc)) PipeOutConstructor#(type ta, type tb);

typeclass ReducePipe#( numeric type n, type a);
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(n,a)) inpipe,
				 PipeOut#(a) ifc);
   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(n,PipeOut#(a)) inpipe,
				  PipeOut#(a) ifc);
endtypeclass
instance ReducePipe#(1, a);
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(1,a)) inpipe,
				 PipeOut#(a) ifc);
      let pipe = mapPipe(head, inpipe);
      return pipe;
   endmodule
   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(1,PipeOut#(a)) inpipes,
				  PipeOut#(a) ifc);
      return inpipes[0];
   endmodule
endinstance
instance ReducePipe#(2, a);
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(2,a)) inpipe,
				 PipeOut#(a) ifc);
      function Tuple2#(a,a) foo(Vector#(2,a) invec); return tuple2(invec[0], invec[1]); endfunction
      PipeOut#(Tuple2#(a,a)) zippipe = mapPipe(foo, inpipe);
      let pipe <- combinepipe(zippipe);
      return pipe;
   endmodule
   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(2,PipeOut#(a)) inpipes,
				  PipeOut#(a) ifc);
      let pipe <- combinepipe(zipPipeOut(inpipes[0], inpipes[1]));
      return pipe;
   endmodule
endinstance

instance ReducePipe#(n, a)
   provisos (Add#(TDiv#(n,2), a__, n),
	     Bits#(Vector#(TDiv#(n,2), a), b__),
	     ReducePipe#(TDiv#(n,2),a));
   module [Module] mkReducePipe (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				 PipeOut#(Vector#(n,a)) inpipe,
				 PipeOut#(a) ifc);
      FIFOF#(Vector#(TDiv#(n,2),a)) infifo0 <- mkFIFOF;
      FIFOF#(Vector#(TDiv#(n,2),a)) infifo1 <- mkFIFOF;
      rule splitinput;
	 let v = inpipe.first();
	 inpipe.deq();
	 infifo0.enq(takeAt(0, v));
	 infifo1.enq(takeAt(valueOf(TDiv#(n,2)), v));
      endrule
      PipeOut#(Vector#(TDiv#(n,2),a)) inpipe0 = toPipeOut(infifo0);
      PipeOut#(Vector#(TDiv#(n,2),a)) inpipe1 = toPipeOut(infifo1);

      PipeOut#(a) p0 <- mkReducePipe(combinepipe, inpipe0);
      PipeOut#(a) p1 <- mkReducePipe(combinepipe, inpipe1);

      PipeOut#(a) outpipe <- combinepipe(zipPipeOut(p0, p1));
      return outpipe;
   endmodule

   module [Module] mkReducePipes (PipeOutConstructor#(Tuple2#(a,a), a) combinepipe,
				  Vector#(n, PipeOut#(a)) inpipes,
				 PipeOut#(a) ifc);
      Vector#(TDiv#(n,2),PipeOut#(a)) pipes0 = takeAt(0, inpipes);
      Vector#(TDiv#(n,2),PipeOut#(a)) pipes1 = takeAt(valueOf(TDiv#(n,2)), inpipes);

      PipeOut#(a) p0 <- mkReducePipes(combinepipe, pipes0);
      PipeOut#(a) p1 <- mkReducePipes(combinepipe, pipes1);

      PipeOut#(a) outpipe <- combinepipe(zipPipeOut(p0, p1));
      return outpipe;
   endmodule
endinstance

interface FirstLastPipe#(type a);
   interface PipeOut#(Tuple2#(Bool,Bool)) pipe;
   method Action start(a count);
endinterface

module mkFirstLastPipe(FirstLastPipe#(a))
   provisos (Bits#(a,asz), Ord#(a), Arith#(a), Eq#(a));
   Reg#(a) countReg <- mkReg(0);
   Reg#(Bool) firstReg <- mkReg(False);
   Reg#(Bool) lastReg <- mkReg(False);
   interface PipeOut pipe;
      method Tuple2#(Bool, Bool) first();
	 return tuple2(firstReg, lastReg);
      endmethod
      method Action deq() if (countReg > 0);
	 firstReg <= False;
	 let c = countReg - 1;
	 if (c == 1)
	    lastReg <= True;
	 countReg <= c;
      endmethod
      method Bool notEmpty();
	 return countReg > 0;
      endmethod
   endinterface
   method Action start(a count) if (countReg == 0);
      firstReg <= True;
      lastReg <= False;
      countReg <= count;
   endmethod
endmodule


shorten critical path in PcieTracer.bsv

shorten critical path in PcieTracer.bsv

Change-Id: I2bae8aac4edca7284e799c390214056d0efbaecd

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

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

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

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

import Vector            :: *;
import Clocks          :: *;
import GetPut            :: *;
import Connectable    :: *;
import FIFO              :: *;
import FIFOF        :: *;
import PCIE               :: *;
import BRAM         :: *;
import BramMux        :: *;

typedef 11 TlpTraceAddrSize;
typedef TAdd#(TlpTraceAddrSize,1) TlpTraceAddrSize1;

typedef struct {
    Bit#(32) timestamp;
    Bit#(7) source;   // 4==frombus 8=tobus
    TLPData#(16) tlp; // 153 bits
} TimestampedTlpData deriving (Bits);
typedef SizeOf#(TimestampedTlpData) TimestampedTlpDataSize;
typedef SizeOf#(TLPData#(16)) TlpData16Size;
typedef SizeOf#(TLPCompletionHeader) TLPCompletionHeaderSize;
interface TlpTrace;
   interface Get#(TimestampedTlpData) tlp;
endinterface

interface TlpTraceData;
   interface Reg#(Bool)     tlpTracing;
   interface Reg#(Bit#(TlpTraceAddrSize)) tlpTraceLimit;
   interface Reg#(Bit#(TlpTraceAddrSize)) pcieTraceBramWrAddr;
   interface BRAMServer#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) bramServer;
   interface BRAMServer#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) bscanBramServer;
endinterface
interface PcieTracer;
   interface Client#(TLPData#(16), TLPData#(16)) pci;
   interface Put#(TimestampedTlpData) trace;
   interface Server#(TLPData#(16), TLPData#(16)) bus;
   interface TlpTraceData tlpdata;
endinterface: PcieTracer

// The PCIe-to-AXI bridge puts all of the elements together
(* synthesize *)
module mkPcieTracer(PcieTracer);
   // Trace Support
   Reg#(Bool) tlpTracingReg        <- mkReg(False);
   Reg#(Bit#(TlpTraceAddrSize)) tlpTraceLimitReg <- mkReg(0);
   FIFOF#(Bit#(TlpTraceAddrSize)) pcieTraceBramWrAddrFifo <- mkFIFOF();
   Reg#(Bit#(TlpTraceAddrSize)) pcieTraceBramWrAddrReg <- mkReg(0);
   Integer memorySize = 2**valueOf(TlpTraceAddrSize);

   BRAM_Configure bramCfg = defaultValue;
   bramCfg.memorySize = memorySize;
   bramCfg.latency = 1;
   BRAM2Port#(Bit#(TlpTraceAddrSize), TimestampedTlpData) fromPcieTraceBram <- mkBRAM2Server(bramCfg);
   BRAM2Port#(Bit#(TlpTraceAddrSize), TimestampedTlpData) toPcieTraceBram <- mkBRAM2Server(bramCfg);
   Vector#(2, BRAMServer#(Bit#(TlpTraceAddrSize), TimestampedTlpData)) bramServers;
   bramServers[0] = fromPcieTraceBram.portA;
   bramServers[1] =   toPcieTraceBram.portA;
   BramServerMux#(TAdd#(TlpTraceAddrSize,1), TimestampedTlpData) bramMuxReg <- mkBramServerMux(bramServers);

//`ifndef BSIM ????? jca
   Vector#(2, BRAMServer#(Bit#(TlpTraceAddrSize), TimestampedTlpData)) bscanBramServers;
   bscanBramServers[0] = fromPcieTraceBram.portB;
   bscanBramServers[1] =   toPcieTraceBram.portB;
   BramServerMux#(TAdd#(TlpTraceAddrSize,1), TimestampedTlpData) bscanBramMux <- mkBramServerMux(bscanBramServers);
//`endif

   Reg#(Bit#(32)) timestamp <- mkReg(0);
   rule incTimestamp;
       timestamp <= timestamp + 1;
   endrule
//   rule endTrace if (tlpTracingReg && tlpTraceLimitReg != 0 && tlpTraceBramWrAddr > truncate(tlpTraceLimitReg));
//       tlpTracingReg <= False;
//   endrule

   FIFO#(TLPData#(16)) tlpFromBusFifo <- mkFIFO();
   FIFO#(TLPData#(16)) tlpToBusFifo <- mkFIFO();
   FIFO#(TLPData#(16)) tlpBusResponseFifo <- mkFIFO();

   Reg#(Bool) skippingIncomingTlps <- mkReg(False);
   FIFO#(Bool) isRootBroadcastMessage <- mkFIFO();
   PulseWire fromPcie <- mkPulseWire;
   PulseWire   toPcie <- mkPulseWire;
   Wire#(TLPData#(16)) fromPcieTlp <- mkDWire(unpack(0));
   Wire#(TLPData#(16))   toPcieTlp <- mkDWire(unpack(0));

   rule sniffTlpFromBus;
      let tlp <- toGet(tlpFromBusFifo).get();
      tlpBusResponseFifo.enq(tlp);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      // skip root_broadcast_messages sent to tlp.hit 0
      isRootBroadcastMessage.enq(tlp.sof && tlp.hit == 0 && hdr_3dw.pkttype != COMPLETION);

   endrule

   rule doTracing if (fromPcie || toPcie);
      TimestampedTlpData fromttd = fromPcie ? TimestampedTlpData { timestamp: timestamp, source: 7'h04, tlp: fromPcieTlp } : unpack(0);
      let writeAddr = pcieTraceBramWrAddrReg;
      if (pcieTraceBramWrAddrFifo.notEmpty)
	 writeAddr <- toGet(pcieTraceBramWrAddrFifo).get();

      fromPcieTraceBram.portA.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: writeAddr, datain: fromttd });

      TimestampedTlpData   tottd = toPcie ? TimestampedTlpData { timestamp: timestamp, source: 7'h08, tlp: toPcieTlp } : unpack(0);
      toPcieTraceBram.portA.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: writeAddr, datain: tottd });

      pcieTraceBramWrAddrReg <= writeAddr + 1;
   endrule

   interface Server     bus;
      interface Get response;
           method ActionValue#(TLPData#(16)) get();
	      let tlp <- toGet(tlpBusResponseFifo).get();

	      if (tlpTracingReg) begin
		 if (tlp.sof && isRootBroadcastMessage.first) begin
 		    skippingIncomingTlps <= True;
		 end
		 else if (skippingIncomingTlps && !tlp.sof) begin
		    // do nothing
		 end
		 else begin
		    fromPcie.send();
		    fromPcieTlp <= tlp;
		    skippingIncomingTlps <= False;
		 end
	      end

	      isRootBroadcastMessage.deq();
	      return tlp;
	   endmethod
      endinterface

       interface Put request;
           method Action put(TLPData#(16) tlp);
           tlpToBusFifo.enq(tlp);
           if (tlpTracingReg) begin
	      toPcie.send();
	      toPcieTlp <= tlp;
           end
           endmethod
       endinterface
   endinterface

   interface Client    pci;
      interface request = toGet(tlpToBusFifo);
      interface response = toPut(tlpFromBusFifo);
   endinterface
   interface Put trace;
       method Action put(TimestampedTlpData ttd) if (!fromPcie && !toPcie);
	   if (tlpTracingReg) begin
	       ttd.timestamp = timestamp;
	       toPcieTraceBram.portA.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: truncate(pcieTraceBramWrAddrReg), datain: ttd });
	       pcieTraceBramWrAddrReg <= pcieTraceBramWrAddrReg + 1;
	   end
       endmethod
   endinterface: trace
   interface TlpTraceData tlpdata;
      interface Reg tlpTracing    = tlpTracingReg;
      interface Reg tlpTraceLimit = tlpTraceLimitReg;
      interface Reg pcieTraceBramWrAddr;
	 method Bit#(TlpTraceAddrSize) _read(); return pcieTraceBramWrAddrReg; endmethod
	 method Action _write(Bit#(TlpTraceAddrSize) v); pcieTraceBramWrAddrFifo.enq(v); endmethod
      endinterface
      interface Server bramServer = bramMuxReg.bramServer;
      interface Server bscanBramServer = bscanBramMux.bramServer;
   endinterface
endmodule: mkPcieTracer

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

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

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

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

import Vector            :: *;
import Clocks          :: *;
import GetPut            :: *;
import Connectable    :: *;
import FIFO              :: *;
import FIFOF        :: *;
import PCIE               :: *;
import BRAM         :: *;
import BramMux        :: *;

typedef 11 TlpTraceAddrSize;
typedef TAdd#(TlpTraceAddrSize,1) TlpTraceAddrSize1;

typedef struct {
    Bit#(32) timestamp;
    Bit#(7) source;   // 4==frombus 8=tobus
    TLPData#(16) tlp; // 153 bits
} TimestampedTlpData deriving (Bits);
typedef SizeOf#(TimestampedTlpData) TimestampedTlpDataSize;
typedef SizeOf#(TLPData#(16)) TlpData16Size;
typedef SizeOf#(TLPCompletionHeader) TLPCompletionHeaderSize;
interface TlpTrace;
   interface Get#(TimestampedTlpData) tlp;
endinterface

interface TlpTraceData;
   interface Reg#(Bool)     tlpTracing;
   interface Reg#(Bit#(TlpTraceAddrSize)) tlpTraceLimit;
   interface Reg#(Bit#(TlpTraceAddrSize)) pcieTraceBramWrAddr;
   interface BRAMServer#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) bramServer;
   interface BRAMServer#(Bit#(TAdd#(TlpTraceAddrSize,1)), TimestampedTlpData) bscanBramServer;
endinterface
interface PcieTracer;
   interface Client#(TLPData#(16), TLPData#(16)) pci;
   interface Put#(TimestampedTlpData) trace;
   interface Server#(TLPData#(16), TLPData#(16)) bus;
   interface TlpTraceData tlpdata;
endinterface: PcieTracer

// The PCIe-to-AXI bridge puts all of the elements together
(* synthesize *)
module mkPcieTracer(PcieTracer);
   // Trace Support
   Reg#(Bool) tlpTracingReg        <- mkReg(False);
   Reg#(Bit#(TlpTraceAddrSize)) tlpTraceLimitReg <- mkReg(0);
   FIFOF#(Bit#(TlpTraceAddrSize)) pcieTraceBramWrAddrFifo <- mkFIFOF();
   Reg#(Bit#(TlpTraceAddrSize)) pcieTraceBramWrAddrReg <- mkReg(0);
   Integer memorySize = 2**valueOf(TlpTraceAddrSize);

   BRAM_Configure bramCfg = defaultValue;
   bramCfg.memorySize = memorySize;
   bramCfg.latency = 1;
   BRAM2Port#(Bit#(TlpTraceAddrSize), TimestampedTlpData) fromPcieTraceBram <- mkBRAM2Server(bramCfg);
   BRAM2Port#(Bit#(TlpTraceAddrSize), TimestampedTlpData) toPcieTraceBram <- mkBRAM2Server(bramCfg);
   Vector#(2, BRAMServer#(Bit#(TlpTraceAddrSize), TimestampedTlpData)) bramServers;
   bramServers[0] = fromPcieTraceBram.portA;
   bramServers[1] =   toPcieTraceBram.portA;
   BramServerMux#(TAdd#(TlpTraceAddrSize,1), TimestampedTlpData) bramMuxReg <- mkBramServerMux(bramServers);

//`ifndef BSIM ????? jca
   Vector#(2, BRAMServer#(Bit#(TlpTraceAddrSize), TimestampedTlpData)) bscanBramServers;
   bscanBramServers[0] = fromPcieTraceBram.portB;
   bscanBramServers[1] =   toPcieTraceBram.portB;
   BramServerMux#(TAdd#(TlpTraceAddrSize,1), TimestampedTlpData) bscanBramMux <- mkBramServerMux(bscanBramServers);
//`endif

   Reg#(Bit#(32)) timestamp <- mkReg(0);
   rule incTimestamp;
       timestamp <= timestamp + 1;
   endrule
//   rule endTrace if (tlpTracingReg && tlpTraceLimitReg != 0 && tlpTraceBramWrAddr > truncate(tlpTraceLimitReg));
//       tlpTracingReg <= False;
//   endrule

   FIFO#(TLPData#(16)) tlpFromBusFifo <- mkFIFO();
   FIFO#(TLPData#(16)) tlpToBusFifo <- mkFIFO();
   Reg#(Bool) skippingIncomingTlps <- mkReg(False);
   PulseWire fromPcie <- mkPulseWire;
   PulseWire   toPcie <- mkPulseWire;
   Wire#(TLPData#(16)) fromPcieTlp <- mkDWire(unpack(0));
   Wire#(TLPData#(16))   toPcieTlp <- mkDWire(unpack(0));

   rule doTracing if (fromPcie || toPcie);
      TimestampedTlpData fromttd = fromPcie ? TimestampedTlpData { timestamp: timestamp, source: 7'h04, tlp: fromPcieTlp } : unpack(0);
      let writeAddr = pcieTraceBramWrAddrReg;
      if (pcieTraceBramWrAddrFifo.notEmpty)
	 writeAddr <- toGet(pcieTraceBramWrAddrFifo).get();

      fromPcieTraceBram.portA.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: writeAddr, datain: fromttd });

      TimestampedTlpData   tottd = toPcie ? TimestampedTlpData { timestamp: timestamp, source: 7'h08, tlp: toPcieTlp } : unpack(0);
      toPcieTraceBram.portA.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: writeAddr, datain: tottd });

      pcieTraceBramWrAddrReg <= writeAddr + 1;
   endrule

   interface Server     bus;
       interface Get response;
           method ActionValue#(TLPData#(16)) get();
           let tlp = tlpFromBusFifo.first;
           tlpFromBusFifo.deq();
           //$display("tlp in: %h\n", tlp);
           if (tlpTracingReg) begin
               TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
               // skip root_broadcast_messages sent to tlp.hit 0
               if (tlp.sof && tlp.hit == 0 && hdr_3dw.pkttype != COMPLETION) begin
 	          skippingIncomingTlps <= True;
	       end
	       else if (skippingIncomingTlps && !tlp.sof) begin
	          // do nothing
	       end
	       else begin
	          fromPcie.send();
	          fromPcieTlp <= tlp;
	           skippingIncomingTlps <= False;
	       end
           end
           return tlp;
           endmethod
       endinterface

       interface Put request;
           method Action put(TLPData#(16) tlp);
           tlpToBusFifo.enq(tlp);
           if (tlpTracingReg) begin
	      toPcie.send();
	      toPcieTlp <= tlp;
           end
           endmethod
       endinterface
   endinterface

   interface Client    pci;
      interface request = toGet(tlpToBusFifo);
      interface response = toPut(tlpFromBusFifo);
   endinterface
   interface Put trace;
       method Action put(TimestampedTlpData ttd) if (!fromPcie && !toPcie);
	   if (tlpTracingReg) begin
	       ttd.timestamp = timestamp;
	       toPcieTraceBram.portA.request.put(BRAMRequest{ write: True, responseOnWrite: False, address: truncate(pcieTraceBramWrAddrReg), datain: ttd });
	       pcieTraceBramWrAddrReg <= pcieTraceBramWrAddrReg + 1;
	   end
       endmethod
   endinterface: trace
   interface TlpTraceData tlpdata;
      interface Reg tlpTracing    = tlpTracingReg;
      interface Reg tlpTraceLimit = tlpTraceLimitReg;
      interface Reg pcieTraceBramWrAddr;
	 method Bit#(TlpTraceAddrSize) _read(); return pcieTraceBramWrAddrReg; endmethod
	 method Action _write(Bit#(TlpTraceAddrSize) v); pcieTraceBramWrAddrFifo.enq(v); endmethod
      endinterface
      interface Server bramServer = bramMuxReg.bramServer;
      interface Server bscanBramServer = bscanBramMux.bramServer;
   endinterface
endmodule: mkPcieTracer


reduce size of adder and eliminate multiplier in 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#(TLog#(nwords)) max  = fromInteger(valueOf(nwords) - 1);
   Bit#(paddingsz) padding = 0;

   FIFOF#(Bit#(aszn)) fifo <- mkFIFOF1();
   Reg#(Bit#(TLog#(nwords)))   count <- mkReg(0);
   Reg#(Bit#(TAdd#(TLog#(asz),1)))   shift <- mkReg(0);

   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 << shift);
      endmethod
      method Action deq() if (fifo.notEmpty);
         if (count == max)
            begin
               count <= 0;
	       shift <= 0;
               fifo.deq;
            end
         else
            begin
               count <= count + 1;
	       shift <= shift + fromInteger(valueOf(n));
            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#(TLog#(nwords)) max    = fromInteger(valueOf(nwords)-1);

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(TLog#(nwords)))    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

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