temp protos of new req/ind for imageon

temp protos of new req/ind for imageon

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

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

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

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

import FIFO::*;
import GetPut::*;
import Connectable :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;
import XbsvSpi :: *;

import GetPutWithClocks :: *;
import Leds::*;
import Imageon::*;
import ImageonVideo::*;
import IserdesDatadeser::*;
import HDMI::*;
import AxiSDMA::*;
import PortalSMemory::*;
import PortalMemory::*;
import BlueScope::*;
import SensorToVideo::*;
import XilinxCells::*;
import XbsvXilinxCells::*;
import YUV::*;

interface CoreIndication;
    method Action iserdes_control_value(Bit#(32) v);
    method Action debugind(Bit#(32) v);
    method Action spi_response(Bit#(32) v);
endinterface

interface CoreRequest;
    method Action set_iserdes_control(Bit#(32) v);
    method Action get_iserdes_control();
    method Action set_decoder_control(Bit#(32) v);
    method Action set_host_oe(Bit#(1) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Action set_decoder_code_ls(Bit#(10) v);
    method Action set_decoder_code_le(Bit#(10) v);
    method Action set_decoder_code_fs(Bit#(10) v);
    method Action set_trigger_default_freq(Bit#(32) v);
    method Action set_trigger_cnt_trigger(Bit#(32) v);
    method Action set_syncgen_delay(Bit#(16) v);
    method Action set_syncgen_hactive(Bit#(16) v);
    method Action set_syncgen_hfporch(Bit#(16) v);
    method Action set_syncgen_hsync(Bit#(16) v);
    method Action set_syncgen_hbporch(Bit#(16) v);
    method Action set_syncgen_vactive(Bit#(16) v);
    method Action set_syncgen_vfporch(Bit#(16) v);
    method Action set_syncgen_vsync(Bit#(16) v);
    method Action set_debugreq(Bit#(32) v);
    method Action get_debugind();
    method Action put_spi_request(Bit#(32) v);
endinterface

interface ImageCaptureIndication;
    interface CoreIndication coreIndication;
    //interface ImageonSensorIndication isIndication;
    //interface ImageonXsviIndication ivIndication;
    interface BlueScopeIndication bsIndication;
    interface DMAIndication dmaIndication;
endinterface

interface ImageCaptureRequest;
   interface CoreRequest coreRequest;
   //interface ImageonSensorRequest isRequest;
   //interface ImageonXsviRequest ivRequest;
   interface BlueScopeRequest bsRequest;
   interface HDMI hdmi;
   interface DMARequest dmaRequest;
   interface ImageonVita vita;
endinterface

module mkImageCaptureRequest#(Clock fmc_imageon_video_clk1, Clock processing_system7_1_fclk_clk3,
    ImageCaptureIndication indication)(ImageCaptureRequest) provisos (Bits#(XsviData,xsviDataWidth));

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    IDELAYCTRL idel <- mkIDELAYCTRL(2, clocked_by processing_system7_1_fclk_clk3);
    Clock imageon_video_clk1_buf_wire <- mkClockIBUFG(clocked_by fmc_imageon_video_clk1);
    MMCMHACK mmcmhack <- mkMMCMHACK(clocked_by imageon_video_clk1_buf_wire);
    Clock hdmi_clock <- mkClockBUFG(clocked_by mmcmhack.mmcmadv.clkout0);
    Clock imageon_clock <- mkClockBUFG(clocked_by mmcmhack.mmcmadv.clkout1);

    Reset imageon_reset <- mkAsyncReset(2, defaultReset, imageon_clock);
    Reset hdmi_reset <- mkAsyncReset(2, defaultReset, hdmi_clock);

    ISerdes serdes <- mkISerdes(defaultClock, defaultReset, clocked_by imageon_clock, reset_by imageon_reset);
    ImageonSensor fromSensor <- mkImageonSensor(defaultClock, defaultReset, serdes.data, clocked_by imageon_clock, reset_by imageon_reset);
    ImageonVideo xsviFromSensor <- mkImageonVideo(imageon_clock, imageon_reset, defaultClock, defaultReset,
        fromSensor, clocked_by hdmi_clock, reset_by hdmi_reset);

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

    SPI#(Bit#(26)) spiController <- mkSPI(1000);

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

    rule xsviConnection;
        let xsvi = xsviFromSensor.get();
        //bsi.dataIn(extend(pack(xsvi)), extend(pack(xsvi)));
        //converter.in.put(xsvi);
        //let xvideo <- converter.out.get();
        //hdmiOut.rgb(xvideo);
        hdmiOut.rgb(Rgb888VideoData{ active_video: xsvi.active_video,
            vsync: xsvi.vsync, hsync: xsvi.hsync,
            r: xsvi.video_data[9:2], g: xsvi.video_data[9:2], b: xsvi.video_data[9:2]});
    endrule

    rule spiControllerResponse;
       Bit#(26) v <- spiController.response.get();
       indication.coreIndication.spi_response(extend(v));
    endrule

    interface CoreRequest coreRequest;
    method Action set_iserdes_control(Bit#(32) v);
        serdes.control.set_iserdes_control(v);
    endmethod
    method Action get_iserdes_control();
        indication.coreIndication.iserdes_control_value(serdes.control.get_iserdes_control());
    endmethod
    method Action set_decoder_control(Bit#(32) v);
        serdes.control.set_decoder_control(v);
    endmethod
    method Action set_host_oe(Bit#(1) v);
        fromSensor.control.set_host_oe(v);
    endmethod
    method Action set_serdes_manual_tap(Bit#(10) v);
        serdes.control.set_serdes_manual_tap(v);
    endmethod
    method Action set_serdes_training(Bit#(10) v);
        serdes.control.set_serdes_training(v);
    endmethod
    method Action set_decoder_code_ls(Bit#(10) v);
        fromSensor.control.set_decoder_code_ls(v);
    endmethod
    method Action set_decoder_code_le(Bit#(10) v);
        fromSensor.control.set_decoder_code_le(v);
    endmethod
    method Action set_decoder_code_fs(Bit#(10) v);
        fromSensor.control.set_decoder_code_fs(v);
    endmethod
    method Action set_trigger_default_freq(Bit#(32) v);
        fromSensor.control.set_trigger_default_freq(v);
    endmethod
    method Action set_trigger_cnt_trigger(Bit#(32) v);
        fromSensor.control.set_trigger_cnt_trigger(v);
    endmethod
    method Action set_syncgen_delay(Bit#(16) v);
        fromSensor.control.set_syncgen_delay(v);
    endmethod
    method Action set_syncgen_hactive(Bit#(16) v);
        xsviFromSensor.control.hactive(v);
    endmethod
    method Action set_syncgen_hfporch(Bit#(16) v);
        xsviFromSensor.control.hfporch(v);
    endmethod
    method Action set_syncgen_hsync(Bit#(16) v);
        xsviFromSensor.control.hsync(v);
    endmethod
    method Action set_syncgen_hbporch(Bit#(16) v);
        xsviFromSensor.control.hbporch(v);
    endmethod
    method Action set_syncgen_vactive(Bit#(16) v);
        xsviFromSensor.control.vactive(v);
    endmethod
    method Action set_syncgen_vfporch(Bit#(16) v);
        xsviFromSensor.control.vfporch(v);
    endmethod
    method Action set_syncgen_vsync(Bit#(16) v);
        xsviFromSensor.control.vsync(v);
    endmethod
    method Action set_debugreq(Bit#(32) v);
    endmethod
    method Action get_debugind();
        indication.coreIndication.debugind(fromSensor.control.get_debugind());
    endmethod
    method Action put_spi_request(Bit#(32) v);
        spiController.request.put(truncate(v));
    endmethod
    endinterface
    //interface ImageonSensorRequest isRequest = fromSensor.control;
    //interface ImageonVideoRequest ivRequest = xsviFromSensor.control;
    interface BlueScopeRequest bsRequest = bsi.requestIfc;
    interface HDMI hdmi = hdmiOut.hdmi;
    interface ImageonVita vita;
        interface ImageonTopPins toppins;
            method Clock fbbozo();
                return mmcmhack.mmcmadv.clkfbout;
            endmethod
            method Action fbbozoin(Bit#(1) v);
                mmcmhack.mmcmadv.clkfbin(v);
            endmethod
        endinterface
        interface SpiPins spi = spiController.pins;
        interface ImageonSensorPins pins = fromSensor.pins;
        interface ImageonSerdesPins serpins = serdes.pins;
    endinterface
endmodule

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

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

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

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

import FIFO::*;
import GetPut::*;
import Connectable :: *;
import PCIE :: *; // ConnectableWithClocks
import Clocks :: *;
import XbsvSpi :: *;

import GetPutWithClocks :: *;
import Leds::*;
import Imageon::*;
import ImageonVideo::*;
import IserdesDatadeser::*;
import HDMI::*;
import AxiSDMA::*;
import PortalSMemory::*;
import PortalMemory::*;
import BlueScope::*;
import SensorToVideo::*;
import XilinxCells::*;
import XbsvXilinxCells::*;
import YUV::*;

interface CoreIndication;
    method Action iserdes_control_value(Bit#(32) v);
    method Action debugind(Bit#(32) v);
    method Action spi_response(Bit#(32) v);
endinterface

interface CoreRequest;
    method Action set_iserdes_control(Bit#(32) v);
    method Action get_iserdes_control();
    method Action set_decoder_control(Bit#(32) v);
    method Action set_host_oe(Bit#(1) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Action set_decoder_code_ls(Bit#(10) v);
    method Action set_decoder_code_le(Bit#(10) v);
    method Action set_decoder_code_fs(Bit#(10) v);
    method Action set_trigger_default_freq(Bit#(32) v);
    method Action set_trigger_cnt_trigger(Bit#(32) v);
    method Action set_syncgen_delay(Bit#(16) v);
    method Action set_syncgen_hactive(Bit#(16) v);
    method Action set_syncgen_hfporch(Bit#(16) v);
    method Action set_syncgen_hsync(Bit#(16) v);
    method Action set_syncgen_hbporch(Bit#(16) v);
    method Action set_syncgen_vactive(Bit#(16) v);
    method Action set_syncgen_vfporch(Bit#(16) v);
    method Action set_syncgen_vsync(Bit#(16) v);
    method Action set_debugreq(Bit#(32) v);
    method Action get_debugind();
    method Action put_spi_request(Bit#(32) v);
endinterface

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

interface ImageCaptureRequest;
   interface CoreRequest coreRequest;
   interface BlueScopeRequest bsRequest;
   interface HDMI hdmi;
   interface DMARequest dmaRequest;
   interface ImageonVita vita;
endinterface

module mkImageCaptureRequest#(Clock fmc_imageon_video_clk1, Clock processing_system7_1_fclk_clk3,
    ImageCaptureIndication indication)(ImageCaptureRequest) provisos (Bits#(XsviData,xsviDataWidth));

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    IDELAYCTRL idel <- mkIDELAYCTRL(2, clocked_by processing_system7_1_fclk_clk3);
    Clock imageon_video_clk1_buf_wire <- mkClockIBUFG(clocked_by fmc_imageon_video_clk1);
    MMCMHACK mmcmhack <- mkMMCMHACK(clocked_by imageon_video_clk1_buf_wire);
    Clock hdmi_clock <- mkClockBUFG(clocked_by mmcmhack.mmcmadv.clkout0);
    Clock imageon_clock <- mkClockBUFG(clocked_by mmcmhack.mmcmadv.clkout1);

    Reset imageon_reset <- mkAsyncReset(2, defaultReset, imageon_clock);
    Reset hdmi_reset <- mkAsyncReset(2, defaultReset, hdmi_clock);

    ISerdes serdes <- mkISerdes(defaultClock, defaultReset, clocked_by imageon_clock, reset_by imageon_reset);
    ImageonSensor fromSensor <- mkImageonSensor(defaultClock, defaultReset, serdes.data, clocked_by imageon_clock, reset_by imageon_reset);
    ImageonVideo xsviFromSensor <- mkImageonVideo(imageon_clock, imageon_reset, defaultClock, defaultReset,
        fromSensor, clocked_by hdmi_clock, reset_by hdmi_reset);

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

    SPI#(Bit#(26)) spiController <- mkSPI(1000);

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

    rule xsviConnection;
        let xsvi = xsviFromSensor.get();
        //bsi.dataIn(extend(pack(xsvi)), extend(pack(xsvi)));
        //converter.in.put(xsvi);
        //let xvideo <- converter.out.get();
        //hdmiOut.rgb(xvideo);
        hdmiOut.rgb(Rgb888VideoData{ active_video: xsvi.active_video,
            vsync: xsvi.vsync, hsync: xsvi.hsync,
            r: xsvi.video_data[9:2], g: xsvi.video_data[9:2], b: xsvi.video_data[9:2]});
    endrule

    rule spiControllerResponse;
       Bit#(26) v <- spiController.response.get();
       indication.coreIndication.spi_response(extend(v));
    endrule

    interface CoreRequest coreRequest;
    method Action set_iserdes_control(Bit#(32) v);
        serdes.control.set_iserdes_control(v);
    endmethod
    method Action get_iserdes_control();
        indication.coreIndication.iserdes_control_value(serdes.control.get_iserdes_control());
    endmethod
    method Action set_decoder_control(Bit#(32) v);
        serdes.control.set_decoder_control(v);
    endmethod
    method Action set_host_oe(Bit#(1) v);
        fromSensor.control.set_host_oe(v);
    endmethod
    method Action set_serdes_manual_tap(Bit#(10) v);
        serdes.control.set_serdes_manual_tap(v);
    endmethod
    method Action set_serdes_training(Bit#(10) v);
        serdes.control.set_serdes_training(v);
    endmethod
    method Action set_decoder_code_ls(Bit#(10) v);
        fromSensor.control.set_decoder_code_ls(v);
    endmethod
    method Action set_decoder_code_le(Bit#(10) v);
        fromSensor.control.set_decoder_code_le(v);
    endmethod
    method Action set_decoder_code_fs(Bit#(10) v);
        fromSensor.control.set_decoder_code_fs(v);
    endmethod
    method Action set_trigger_default_freq(Bit#(32) v);
        fromSensor.control.set_trigger_default_freq(v);
    endmethod
    method Action set_trigger_cnt_trigger(Bit#(32) v);
        fromSensor.control.set_trigger_cnt_trigger(v);
    endmethod
    method Action set_syncgen_delay(Bit#(16) v);
        fromSensor.control.set_syncgen_delay(v);
    endmethod
    method Action set_syncgen_hactive(Bit#(16) v);
        xsviFromSensor.control.hactive(v);
    endmethod
    method Action set_syncgen_hfporch(Bit#(16) v);
        xsviFromSensor.control.hfporch(v);
    endmethod
    method Action set_syncgen_hsync(Bit#(16) v);
        xsviFromSensor.control.hsync(v);
    endmethod
    method Action set_syncgen_hbporch(Bit#(16) v);
        xsviFromSensor.control.hbporch(v);
    endmethod
    method Action set_syncgen_vactive(Bit#(16) v);
        xsviFromSensor.control.vactive(v);
    endmethod
    method Action set_syncgen_vfporch(Bit#(16) v);
        xsviFromSensor.control.vfporch(v);
    endmethod
    method Action set_syncgen_vsync(Bit#(16) v);
        xsviFromSensor.control.vsync(v);
    endmethod
    method Action set_debugreq(Bit#(32) v);
    endmethod
    method Action get_debugind();
        indication.coreIndication.debugind(fromSensor.control.get_debugind());
    endmethod
    method Action put_spi_request(Bit#(32) v);
        spiController.request.put(truncate(v));
    endmethod
    endinterface
    interface BlueScopeRequest bsRequest = bsi.requestIfc;
    interface HDMI hdmi = hdmiOut.hdmi;
    interface ImageonVita vita;
        interface ImageonTopPins toppins;
            method Clock fbbozo();
                return mmcmhack.mmcmadv.clkfbout;
            endmethod
            method Action fbbozoin(Bit#(1) v);
                mmcmhack.mmcmadv.clkfbin(v);
            endmethod
        endinterface
        interface SpiPins spi = spiController.pins;
        interface ImageonSensorPins pins = fromSensor.pins;
        interface ImageonSerdesPins serpins = serdes.pins;
    endinterface
endmodule


add missing display, fixed gap weight, now gets right answer

// 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 GotohB::*;
import StackReg::*;

interface SWAlgorithm;
   method Action setupA (Bit#(14) start, Bit#(14) length);
   method Action setupB (Bit#(14) start, Bit#(14) length);
   method Bit#(14) result();
   interface FSM fsm;
endinterface

/* frame arguments */
typedef struct {
   Bit#(14) aStart;
   Bit#(14) bStart;
   Bit#(14) aLen;
   Bit#(14) bLen;
   Bit#(16) tb; /* tb, te only need to be 1 bit, to represent 0 or g */
   Bit#(16) te;
   } CArgs deriving(Bits);

typedef struct {
   Bit#(14) midi;
   Bit#(14) minj;
   Bit#(2) mintype;
   } CVars deriving(Bits);

typedef enum {GCSIdle, GCS1, GCS2, GCS3, GCS4, GCS5, GCS6,
   GCSComplete} GCState deriving (Bits, Eq);

module mkGotohC#(
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA,
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB,
   GotohAlgorithm cgotohB0,
   GotohAlgorithm cgotohB1,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) cc,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) dd,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) rr,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) ss)(SWAlgorithm)
   provisos(Add#(0, 14, strIndexWidth),
	    Add#(0, 14, lIndexWidth));

   Bit#(16) initialH = 1;
   Bit#(16) initialG = 4;
      /* pc, args, vars */
   StackReg#(128, GCState, CArgs, CVars) fr <- mkStackReg(128, GCSIdle);

   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#(14)) outcounter <- mkReg(0);
   Reg#(Bit#(16)) alt1 <- mkReg(0);
   Reg#(Bit#(16)) alt2 <- mkReg(0);
   Reg#(Bit#(16)) minsofar <- mkReg(0);
   Reg#(Bit#(1)) minfound <- mkReg(0);

/*
 * GotohC(Astart, Alen, Bstart, Blen, tb, te, output fifo)
 * implicit A storage, B storage
 *
 */
   function Bit#(16) gap (Bit#(16) i);

      if (i == 0) gap = 0;
      else gap = (initialG + (initialH * i));
      endfunction: gap

  // This FSM searches string B looking for the first char of string A
   Stmt gotohC2Stmt =
   seq
      $display("gotohC2Stmt running ");
      // read A[0]
      strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.aStart, datain: ?});
      action
	 let tmp <- strA.response.get();
	 aData <= tmp;
      endaction
      alt1 <= min(fr.args.tb, fr.args.te) + initialH + gap(zeroExtend(fr.args.bLen));
      minsofar <= alt1;
      fr.vars <= CVars{midi: 0, minj: 1, mintype: 1};
      // scan B
      for (jj <= 1; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.bStart + jj - 1, datain: ?});
	    action
	       let tmp <- strB.response.get();
	       bData <= tmp;
	    endaction
	    if (aData == bData)
	       alt2 <= 0;
	    else
	       alt2 <= 2;
	    alt2 <= alt2 + gap(zeroExtend(jj - 1)) + gap(zeroExtend(fr.args.bLen - jj));
	    if (min(alt1, alt2) < minsofar)
	       par
		  minsofar <= min(alt1, alt2);
		  fr.vars <= CVars{midi: 0, minj: jj, mintype: 1};
	       endpar
	 endseq
      if (fr.vars.minj > 1)
	 $display("delete B[%d] through B[%d]",
	    fr.args.bStart, fr.args.bStart + fr.vars.minj - 1);
      $display("convert A[%d] (%s) to B[%d] (%s)",
	       fr.args.aStart, aData, fr.args.bStart + fr.vars.minj - 1, bData);
      if (fr.vars.minj < fr.args.bLen)
	 $display("delete B[%d] through B[%d]",
		  fr.args.bStart + fr.vars.minj, fr.args.bStart + fr.args.bLen - 1);
      $display("notes fr.vars.minj %f fr.args.bLen %d",
	 fr.vars.minj, fr.args.bLen);
      fr.doreturn();
   endseq;

   FSM gC2fsm <- mkFSM(gotohC2Stmt);

   // AlgC step 1, 2, and 3
   rule gc1 (fr.pc == GCS1);
      $display("GCS1 aStart %d aLen %d bStart %d bLen %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen);
      if (fr.args.bLen == 0)
	 begin
	    if (fr.args.aLen > 0)
	       $display("delete A[%d] through A[%d]",
		  fr.args.aStart, fr.args.aStart + fr.args.aLen - 1);
	    fr.doreturn();
	 end
     else if (fr.args.aLen == 0)
	begin
	   $display("insert B[%d] through B[%d]",
	      fr.args.bStart, fr.args.bStart + fr.args.bLen - 1);
	end
     else if (fr.args.aLen == 1)
	begin
	   gC2fsm.start();
	   fr.nextpc(GCS2);
	end
     else
	action
	   let midi = fr.args.aLen >> 1;
	   fr.vars.midi <= midi;
	   cgotohB1.setupA(fr.args.aStart, midi);
	   cgotohB1.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB1.setupG(fr.args.tb);
	   cgotohB0.setupA(fr.args.aStart+midi, fr.args.aLen - midi);
	   cgotohB0.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB0.setupG(fr.args.te);
	   cgotohB0.fsm.start();
	   cgotohB1.fsm.start();
	   fr.nextpc(GCS3);
	endaction
   endrule

   // This FSM searches the results of the two calls to GotohB
   Stmt gotohC4Stmt =
   seq
      $display ("gotohC4A stmt running");
      action
	 minfound <= 0;
	 minsofar <= 0;
	 fr.vars.minj <= 0;
      endaction
      for (jj <= 0; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    action
	       cc.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	       rr.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	       dd.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	       ss.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	    endaction
	    action
	       let tc <- cc.response.get();
	       let td <- dd.response.get();
	       let tr <- rr.response.get();
	       let ts <- ss.response.get();
	       let t1 = tc + tr;
	       let t2 = td + ts - initialG;
	       $display(" j %d cc %d dd %d rr %d ss %d",
		  jj, tc, td, tr, ts);
	       if ((minfound == 0) || (t1 < minsofar) || (t2 < minsofar))
		  action
		     if (t1 < t2)
			action
			   fr.vars <= CVars{midi: fr.vars.midi, minj: jj, mintype: 1};
			   minsofar <= t1;
			endaction
		     else
			action
			   fr.vars <= CVars{midi: fr.vars.midi, minj: jj, mintype: 2};
			   minsofar <= t2;
			endaction
		  endaction
	       minfound <= 1;
	    endaction
	 endseq
      $display ("midi %d minj %d fr.vars.mintype %d",
	 fr.vars.midi, fr.vars.minj, fr.vars.mintype);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: initialG}, fr.vars);
	 endaction
      else /* fr.vars.mintype == 2 */
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi - 1, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: 0}, fr.vars);
	 endaction
   endseq;

   FSM gc4fsm <- mkFSM(gotohC4Stmt);

   rule gc3 (fr.pc == GCS3 && cgotohB0.fsm.done() && cgotohB1.fsm.done());
      //$display("HSC3");
      gc4fsm.start();
      fr.nextpc(GCS4);
   endrule

   rule gc5 (fr.pc == GCS5);
      $display("GCC5 aStart %d aLen %d bStart %d bLen %d midi %d maj %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen,
	 fr.vars.midi, fr.vars.minj);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi, aLen: fr.args.aLen - fr.vars.midi, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj, tb: initialG, te: fr.args.te}, fr.vars);
	 endaction
      else
	 action
	    $display("delete A[%d] and A[%d]",
	       fr.args.aStart + fr.vars.midi,
	       fr.args.aStart + fr.vars.midi + 1);
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi + 1, aLen: fr.args.aLen - fr.vars.midi- 1, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj, tb: 0, te: fr.args.te}, fr.vars);
	 endaction
   endrule

   rule gc6 (fr.pc == GCS6);
      $display("GSC6");
      fr.doreturn();
   endrule

   rule hccomplete (fr.pc == GCSComplete);
      $display("GSCComplete, result size %d", outcounter);
      fr.nextpc(GCSIdle);
   endrule

   method Action setupA(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupA %d %d", start, length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupB %d %d", start, length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Bit#(14) result();
      return(outcounter);
   endmethod

   interface FSM fsm;
      method Action start();
         $display("GotohC running aLen %d bLen %d", aLenReg, bLenReg);
	 fr.docall(GCS1, GCSComplete, CArgs{aStart: 0, aLen: aLenReg,
	    bStart: 0, bLen: bLenReg, tb: initialG, te: initialG}, CVars {midi: 0, minj: 0, mintype: 1});
      endmethod
      method Bool done();
	 return(fr.pc == GCSIdle);
      endmethod
      method Action waitTillDone();
      endmethod
      method Action abort();
      endmethod
   endinterface: fsm

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 GotohB::*;
import StackReg::*;

interface SWAlgorithm;
   method Action setupA (Bit#(14) start, Bit#(14) length);
   method Action setupB (Bit#(14) start, Bit#(14) length);
   method Bit#(14) result();
   interface FSM fsm;
endinterface

/* frame arguments */
typedef struct {
   Bit#(14) aStart;
   Bit#(14) bStart;
   Bit#(14) aLen;
   Bit#(14) bLen;
   Bit#(16) tb; /* tb, te only need to be 1 bit, to represent 0 or g */
   Bit#(16) te;
   } CArgs deriving(Bits);

typedef struct {
   Bit#(14) midi;
   Bit#(14) minj;
   Bit#(2) mintype;
   } CVars deriving(Bits);

typedef enum {GCSIdle, GCS1, GCS2, GCS3, GCS4, GCS5, GCS6,
   GCSComplete} GCState deriving (Bits, Eq);

module mkGotohC#(
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA,
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB,
   GotohAlgorithm cgotohB0,
   GotohAlgorithm cgotohB1,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) cc,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) dd,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) rr,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) ss)(SWAlgorithm)
   provisos(Add#(0, 14, strIndexWidth),
	    Add#(0, 14, lIndexWidth));

   Bit#(16) initialH = 1;
   Bit#(16) initialG = 4;
      /* pc, args, vars */
   StackReg#(128, GCState, CArgs, CVars) fr <- mkStackReg(128, GCSIdle);

   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#(14)) outcounter <- mkReg(0);
   Reg#(Bit#(16)) alt1 <- mkReg(0);
   Reg#(Bit#(16)) alt2 <- mkReg(0);
   Reg#(Bit#(16)) minsofar <- mkReg(0);
   Reg#(Bit#(1)) minfound <- mkReg(0);

/*
 * GotohC(Astart, Alen, Bstart, Blen, tb, te, output fifo)
 * implicit A storage, B storage
 *
 */
   function Bit#(16) gap (Bit#(16) i);

      if (i == 0) gap = 0;
      else gap = (initialG + (initialH * i));
      endfunction: gap

  // This FSM searches string B looking for the first char of string A
   Stmt gotohC2Stmt =
   seq
      $display("gotohC2Stmt running ");
      // read A[0]
      strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.aStart, datain: ?});
      action
	 let tmp <- strA.response.get();
	 aData <= tmp;
      endaction
      alt1 <= min(fr.args.tb, fr.args.te) + gap(zeroExtend(fr.args.bLen));
      minsofar <= alt1;
      fr.vars.minj <= 1;
      // scan B
      for (jj <= 1; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.bStart + jj - 1, datain: ?});
	    action
	       let tmp <- strB.response.get();
	       bData <= tmp;
	    endaction
	    if (aData == bData)
	       alt2 <= 0;
	    else
	       alt2 <= 2;
	    alt2 <= alt2 + gap(zeroExtend(jj - 1)) + gap(zeroExtend(fr.args.bLen - jj));
	    if (min(alt1, alt2) < minsofar)
	       par
		  minsofar <= min(alt1, alt2);
		  fr.vars.minj <= jj;
	       endpar
	 endseq
      if (fr.vars.minj > 1)
	 $display("delete B[%d] through B[%d]",
	    fr.args.bStart, fr.args.bStart + fr.vars.minj - 1);
      $display("convert A[%d] (%s) to B[%d] (%s)",
	       fr.args.aStart, aData, fr.args.bStart + fr.vars.minj - 1, bData);
      if (fr.vars.minj < fr.args.bLen)
	 $display("delete B[%d] through B[%d]",
		  fr.args.bStart + fr.vars.minj, fr.args.bStart + fr.args.bLen - 1);
      fr.doreturn();
   endseq;

   FSM gC2fsm <- mkFSM(gotohC2Stmt);

   // AlgC step 1, 2, and 3
   rule gc1 (fr.pc == GCS1);
      $display("GCS1 aStart %d aLen %d bStart %d bLen %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen);
      if (fr.args.bLen == 0)
	 begin
	    $display("delete A[%d] through A[%d]",
	       fr.args.aStart, fr.args.aStart + fr.args.aLen - 1);
	    fr.doreturn();
	 end
     else if (fr.args.bLen == 0)
	begin
	   $display("insert B[%d] through B[%d]",
	      fr.args.bStart, fr.args.bStart + fr.args.bLen - 1);
	end
     else if (fr.args.aLen == 1)
	begin
	   gC2fsm.start();
	   fr.nextpc(GCS2);
	end
     else
	action
	   let midi = fr.args.aLen >> 1;
	   fr.vars.midi <= midi;
	   cgotohB1.setupA(fr.args.aStart, midi);
	   cgotohB1.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB1.setupG(fr.args.tb);
	   cgotohB0.setupA(fr.args.aStart+midi, fr.args.aLen - midi);
	   cgotohB0.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB0.setupG(fr.args.te);
	   cgotohB0.fsm.start();
	   cgotohB1.fsm.start();
	   fr.nextpc(GCS3);
	endaction
   endrule

   // This FSM searches the results of the two calls to GotohB
   Stmt gotohC4Stmt =
   seq
      $display ("gotohC4A stmt running");
      action
	 minfound <= 0;
	 minsofar <= 0;
	 fr.vars.minj <= 0;
      endaction
      for (jj <= 0; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    action
	       cc.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	       rr.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	       dd.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	       ss.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	    endaction
	    action
	       let tc <- cc.response.get();
	       let td <- dd.response.get();
	       let tr <- rr.response.get();
	       let ts <- ss.response.get();
	       let t1 = tc + tr;
	       let t2 = td + ts;
	       $display(" j %d cc %d dd %d rr %d ss %d",
		  jj, tc, td, tr, ts);
	       if ((minfound == 0) || (t1 < minsofar) || (t2 < minsofar))
		  action
		     if (t1 < t2)
			action
			   fr.vars <= CVars{midi: fr.vars.midi, minj: jj, mintype: 1};
			   minsofar <= t1;
			endaction
		     else
			action
			   fr.vars <= CVars{midi: fr.vars.midi, minj: jj, mintype: 2};
			   minsofar <= t2;
			endaction
		  endaction
	       minfound <= 1;
	    endaction
	 endseq
      $display ("midi %d minj %d fr.vars.mintype %d",
	 fr.vars.midi, fr.vars.minj, fr.vars.mintype);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: initialG}, fr.vars);
	 endaction
      else /* fr.vars.mintype == 2 */
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi - 1, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: 0}, fr.vars);
	 endaction
   endseq;

   FSM gc4fsm <- mkFSM(gotohC4Stmt);

   rule gc3 (fr.pc == GCS3 && cgotohB0.fsm.done() && cgotohB1.fsm.done());
      //$display("HSC3");
      gc4fsm.start();
      fr.nextpc(GCS4);
   endrule

   rule gc5 (fr.pc == GCS5);
      $display("GCC5 aStart %d aLen %d bStart %d bLen %d midi %d maj %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen,
	 fr.vars.midi, fr.vars.minj);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi, aLen: fr.args.aLen - fr.vars.midi, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj, tb: initialG, te: fr.args.te}, fr.vars);
	 endaction
      else
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi + 1, aLen: fr.args.aLen - fr.vars.midi- 1, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj, tb: 0, te: fr.args.te}, fr.vars);
	 endaction
   endrule

   rule gc6 (fr.pc == GCS6);
      $display("GSC6");
      fr.doreturn();
   endrule

   rule hccomplete (fr.pc == GCSComplete);
      $display("GSCComplete, result size %d", outcounter);
      fr.nextpc(GCSIdle);
   endrule

   method Action setupA(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupA %d %d", start, length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupB %d %d", start, length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Bit#(14) result();
      return(outcounter);
   endmethod

   interface FSM fsm;
      method Action start();
         $display("GotohC running aLen %d bLen %d", aLenReg, bLenReg);
	 fr.docall(GCS1, GCSComplete, CArgs{aStart: 0, aLen: aLenReg,
	    bStart: 0, bLen: bLenReg, tb: initialG, te: initialG}, CVars {midi: 0, minj: 0, mintype: 1});
      endmethod
      method Bool done();
	 return(fr.pc == GCSIdle);
      endmethod
      method Action waitTillDone();
      endmethod
      method Action abort();
      endmethod
   endinterface: fsm

endmodule


Added performGenericAtomicMemOpOnReg

Added performGenericAtomicMemOpOnReg

// Copyright (c) 2017 Massachusetts Institute of Technology

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

/**
 * This package contains types, interfaces, and modules for a generic memory
 * type that supports atomic memory operations.
 *
 * The motivation behind this package is to give base memory implementations
 * that can be built upon to produce specialized memory interfaces.
 */
package GenericAtomicMem;

import BRAMCore::*;
import BuildVector::*;
import RegFile::*;
import Vector::*;

import Ehr::*;
import FIFOG::*;
import Port::*;

typedef struct {
    Bit#(writeEnSz) write_en;
    atomicMemOpT atomic_op;
    Bit#(wordAddrSz) word_addr;
    Bit#(dataSz) data;
} GenericAtomicMemReq#(numeric type writeEnSz, type atomicMemOpT, numeric type wordAddrSz, numeric type dataSz) deriving (Bits, Eq, FShow);

typedef struct {
    Bool write;
    Bit#(dataSz) data;
} GenericAtomicMemResp#(numeric type dataSz) deriving (Bits, Eq, FShow);

typedef ServerPort#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz), GenericAtomicMemResp#(dataSz))
        GenericAtomicMemServerPort#(numeric type writeEnSz, type atomicMemOpT, numeric type wordAddrSz, numeric type dataSz);

typedef ClientPort#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz), GenericAtomicMemResp#(dataSz))
        GenericAtomicMemClientPort#(numeric type writeEnSz, type atomicMemOpT, numeric type wordAddrSz, numeric type dataSz);

////////////////////////////////////////////////////////////////////////////////

// AtomicMemOp types, typeclasses, and instances

typeclass IsAtomicMemOp#(type atomicMemOpT);
    function atomicMemOpT nonAtomicMemOp;
    function Bool isAtomicMemOp(atomicMemOpT op);
endtypeclass

typeclass HasAtomicMemOpFunc#(type atomicMemOpT, numeric type dataSz, numeric type writeEnSz)
        provisos (IsAtomicMemOp#(atomicMemOpT));
    function Bit#(dataSz) atomicMemOpFunc(atomicMemOpT op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
endtypeclass

typedef void AMONone;

typedef enum {
    None,
    Swap
} AMOSwap deriving (Bits, Eq, FShow, Bounded);

typedef enum {
    None,
    Swap,
    And,
    Or,
    Xor
} AMOLogical deriving (Bits, Eq, FShow, Bounded);

typedef enum {
    None,
    Swap,
    And,
    Or,
    Xor,
    Add,
    Min,
    Max,
    Minu,
    Maxu
} AMOArithmetic deriving (Bits, Eq, FShow, Bounded);

/// This function extends byte enables into bit enables.
function Bit#(dataSz) writeEnExtend(Bit#(writeEnSz) write_en)
        provisos (Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz));
    Vector#(writeEnSz, Bit#(1)) write_en_vec = unpack(write_en);
    return pack(map(signExtend, write_en_vec));
endfunction

function Bit#(dataSz) emulateWriteEn(Bit#(dataSz) memData, Bit#(dataSz) writeData, Bit#(writeEnSz) writeEn)
        provisos (Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz));
    Bit#(dataSz) bitEn = writeEnExtend(writeEn);
    return (writeData & bitEn) | (memData & ~bitEn);
endfunction

instance IsAtomicMemOp#(AMONone);
    function AMONone nonAtomicMemOp = ?;
    function Bool isAtomicMemOp(AMONone op) = False;
endinstance
instance HasAtomicMemOpFunc#(AMONone, dataSz, writeEnSz);
    function Bit#(dataSz) atomicMemOpFunc(AMONone op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        return operandData;
    endfunction
endinstance

instance IsAtomicMemOp#(AMOSwap);
    function AMOSwap nonAtomicMemOp = None;
    function Bool isAtomicMemOp(AMOSwap op) = (op != None);
endinstance
instance HasAtomicMemOpFunc#(AMOSwap, dataSz, writeEnSz);
    function Bit#(dataSz) atomicMemOpFunc(AMOSwap op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        return operandData;
    endfunction
endinstance

instance IsAtomicMemOp#(AMOLogical);
    function AMOLogical nonAtomicMemOp = None;
    function Bool isAtomicMemOp(AMOLogical op) = (op != None);
endinstance
instance HasAtomicMemOpFunc#(AMOLogical, dataSz, writeEnSz);
    function Bit#(dataSz) atomicMemOpFunc(AMOLogical op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        return (case (op)
                    None: operandData;
                    Swap: operandData;
                    And:  (operandData & memData);
                    Or:   (operandData | memData);
                    Xor:  (operandData ^ memData);
                    default: operandData;
                endcase);
    endfunction
endinstance

instance IsAtomicMemOp#(AMOArithmetic);
    function AMOArithmetic nonAtomicMemOp = None;
    function Bool isAtomicMemOp(AMOArithmetic op) = (op != None);
endinstance
instance HasAtomicMemOpFunc#(AMOArithmetic, dataSz, writeEnSz)
        provisos(Mul#(writeEnSz, byteSz, dataSz),
                 Add#(a__, 1, dataSz),
                 Add#(b__, 1, byteSz));
    function Bit#(dataSz) atomicMemOpFunc(AMOArithmetic op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        Bit#(dataSz) bitEn = writeEnExtend(writeEn);
        Vector#(writeEnSz, Bit#(byteSz)) memDataVec = unpack(memData);
        Vector#(writeEnSz, Bit#(byteSz)) operandDataVec = unpack(operandData);
        Bit#(1) memDataMSB = 0;
        Bit#(1) operandDataMSB = 0;
        Bool isSigned = ((op == Min) || (op == Max));
        for (Integer i = 0 ; i < valueOf(writeEnSz) ; i = i+1) begin
            if (writeEn[i] == 1) begin
                memDataMSB = msb(memDataVec[i]);
                operandDataMSB = msb(operandDataVec[i]);
            end
        end

        Bit#(dataSz) maskedMemData = (memData & bitEn) | (isSigned ? (signExtend(memDataMSB) & ~bitEn) : 0);
        Bit#(dataSz) maskedOperandData = (operandData & bitEn) | (isSigned ? (signExtend(operandDataMSB) & ~bitEn) : 0);

        Int#(TAdd#(1,dataSz)) memInt = unpack(isSigned ? signExtend(maskedMemData) : zeroExtend(maskedMemData));
        Int#(TAdd#(1,dataSz)) operandInt = unpack(isSigned ? signExtend(maskedOperandData) : zeroExtend(maskedOperandData));
        Bool operandDataLarger = operandInt > memInt;

        return (case (op)
                    None: operandData;
                    Swap: operandData;
                    And:  (operandData & memData);
                    Or:   (operandData | memData);
                    Xor:  (operandData ^ memData);
                    Add:  ((operandData & bitEn) + (memData & bitEn));
                    Min:  (operandDataLarger ? memData : operandData);
                    Max:  (operandDataLarger ? operandData : memData);
                    Minu: (operandDataLarger ? memData : operandData);
                    Maxu: (operandDataLarger ? operandData : memData);
                    default: operandData;
                endcase);
    endfunction
endinstance

////////////////////////////////////////////////////////////////////////////////

// Memory implementations

typedef struct {
    Bit#(writeEnSz) write_en;
    atomicMemOpT atomic_op;
    Bool rmw_write;
} GenericAtomicBRAMPendingReq#(numeric type writeEnSz, type atomicMemOpT) deriving (Bits, Eq, FShow);

/// This function is needed because BRAMCore does not support write enables
/// that are not 8 or 9 bits wide.
function BRAM_PORT_BE#(addrT, dataT, writeEnSz) to_BRAM_PORT_BE(BRAM_PORT#(addrT, dataT) bram);
    return (interface BRAM_PORT_BE;
                method Action put(Bit#(writeEnSz) writeen, addrT addr, dataT data);
                    bram.put(writeen != 0, addr, data);
                endmethod
                method dataT read = bram.read;
            endinterface);
endfunction

function BRAM_DUAL_PORT_BE#(addrT, dataT, writeEnSz) to_BRAM_DUAL_PORT_BE(BRAM_DUAL_PORT#(addrT, dataT) bram);
    return (interface BRAM_DUAL_PORT_BE;
                interface BRAM_PORT_BE a;
                    method Action put(Bit#(writeEnSz) writeen, addrT addr, dataT data);
                        bram.a.put(writeen != 0, addr, data);
                    endmethod
                    method dataT read = bram.a.read;
                endinterface
                interface BRAM_PORT_BE b;
                    method Action put(Bit#(writeEnSz) writeen, addrT addr, dataT data);
                        bram.b.put(writeen != 0, addr, data);
                    endmethod
                    method dataT read = bram.b.read;
                endinterface
            endinterface);
endfunction

/// This type matches the LoadFormat type in the Bluespec Reference Guide
typedef union tagged {
    void   None;
    String Hex;
    String Binary;
} LoadFormat deriving (Bits, Eq);

module mkGenericAtomicBRAM#(Integer numWords)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(TDiv#(dataSz, writeEnSz), writeEnSz, dataSz),
                  Bits#(atomicMemOpT, atomicMemOpSz));
    let _m <- mkGenericAtomicBRAMLoad(numWords, tagged None);
    return _m;
endmodule

module mkGenericAtomicBRAMLoad#(Integer numWords, LoadFormat loadFile)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(TDiv#(dataSz, writeEnSz), writeEnSz, dataSz), // This is needed for mkBRAMCore1BE
                  Bits#(atomicMemOpT, atomicMemOpSz));
    // If numWords == 0, then assume the entire address space is used
    Integer actualNumWords = numWords == 0 ? valueOf(TExp#(wordAddrSz)) : numWords;

    // Instantiate the BRAM
    BRAM_PORT_BE#(Bit#(wordAddrSz), Bit#(dataSz), writeEnSz) bram;
    if (valueOf(writeEnSz) == 1) begin
        BRAM_PORT#(Bit#(wordAddrSz), Bit#(dataSz)) bram_non_be;
        case (loadFile) matches
            tagged None: bram_non_be <- mkBRAMCore1(actualNumWords, False);
            tagged Hex .hexfile: bram_non_be <- mkBRAMCore1Load(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram_non_be <- mkBRAMCore1Load(actualNumWords, False, binfile, True);
        endcase
        bram = to_BRAM_PORT_BE(bram_non_be);
    end else begin
        case (loadFile) matches
            tagged None: bram <- mkBRAMCore1BE(actualNumWords, False);
            tagged Hex .hexfile: bram <- mkBRAMCore1BELoad(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram <- mkBRAMCore1BELoad(actualNumWords, False, binfile, True);
        endcase
    end

    Ehr#(2, Maybe#(GenericAtomicBRAMPendingReq#(writeEnSz, atomicMemOpT))) pendingReq <- mkEhr(tagged Invalid);
    FIFOG#(GenericAtomicMemResp#(dataSz)) pendingResp <- mkBypassFIFOG;
    Reg#(Bit#(wordAddrSz)) atomicOpWordAddr <- mkReg(0);
    Reg#(Bit#(dataSz)) atomicOpData <- mkReg(0);

    rule performAtomicMemoryOp( pendingReq[0] matches tagged Valid .req
                                &&& isAtomicMemOp(req.atomic_op));
        let writeData = atomicMemOpFunc(req.atomic_op, bram.read, atomicOpData, req.write_en);
        bram.put(req.write_en, atomicOpWordAddr, writeData);
        pendingReq[0] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: nonAtomicMemOp, rmw_write: True };
        atomicOpData <= bram.read;
    endrule

    rule getRespFromCore( pendingReq[0] matches tagged Valid .req
                          &&& !isAtomicMemOp(req.atomic_op));
        pendingResp.enq(GenericAtomicMemResp{ write: req.write_en != 0, data: (req.rmw_write ? atomicOpData : bram.read) });
        pendingReq[0] <= tagged Invalid;
    endrule

    interface InputPort request;
        method Action enq(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req) if (!isValid(pendingReq[1]));
            let atomic_op = (req.write_en == 0) ? nonAtomicMemOp : req.atomic_op;
            if (isAtomicMemOp(atomic_op)) begin
                bram.put(0, req.word_addr, req.data);
                atomicOpWordAddr <= req.word_addr;
                atomicOpData <= req.data;
            end else begin
                bram.put(req.write_en, req.word_addr, req.data);
            end
            pendingReq[1] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: atomic_op, rmw_write: False };
        endmethod
        method Bool canEnq;
            return !isValid(pendingReq[1]);
        endmethod
    endinterface
    interface OutputPort response = toOutputPort(pendingResp);
endmodule

module mkGenericAtomicBRAMLoad2Port#(Integer numWords, LoadFormat loadFile)(Vector#(2, GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(TDiv#(dataSz, writeEnSz), writeEnSz, dataSz), // This is needed for mkBRAMCore1BE
                  Bits#(atomicMemOpT, atomicMemOpSz));
    // If numWords == 0, then assume the entire address space is used
    Integer actualNumWords = numWords == 0 ? valueOf(TExp#(wordAddrSz)) : numWords;

    // Instantiate the BRAM
    BRAM_DUAL_PORT_BE#(Bit#(wordAddrSz), Bit#(dataSz), writeEnSz) bram;
    if (valueOf(writeEnSz) == 1) begin
        BRAM_DUAL_PORT#(Bit#(wordAddrSz), Bit#(dataSz)) bram_non_be;
        case (loadFile) matches
            tagged None: bram_non_be <- mkBRAMCore2(actualNumWords, False);
            tagged Hex .hexfile: bram_non_be <- mkBRAMCore2Load(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram_non_be <- mkBRAMCore2Load(actualNumWords, False, binfile, True);
        endcase
        bram = to_BRAM_DUAL_PORT_BE(bram_non_be);
    end else begin
        case (loadFile) matches
            tagged None: bram <- mkBRAMCore2BE(actualNumWords, False);
            tagged Hex .hexfile: bram <- mkBRAMCore2BELoad(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram <- mkBRAMCore2BELoad(actualNumWords, False, binfile, True);
        endcase
    end

    Vector#(2, BRAM_PORT_BE#(Bit#(wordAddrSz), Bit#(dataSz), writeEnSz)) bramVec = vec(bram.a, bram.b);
    Vector#(2, Ehr#(2, Maybe#(GenericAtomicBRAMPendingReq#(writeEnSz, atomicMemOpT)))) pendingReq <- replicateM(mkEhr(tagged Invalid));
    Vector#(2, FIFOG#(GenericAtomicMemResp#(dataSz))) pendingResp <- replicateM(mkBypassFIFOG);
    Vector#(2, Reg#(Bit#(wordAddrSz))) atomicOpWordAddr <- replicateM(mkReg(0));
    Vector#(2, Reg#(Bit#(dataSz))) atomicOpData <- replicateM(mkReg(0));

    Vector#(2, GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)) ifc;

    for (Integer i = 0 ; i < 2 ; i = i+1) begin
        rule performAtomicMemoryOp( pendingReq[i][0] matches tagged Valid .req
                                    &&& isAtomicMemOp(req.atomic_op));
            let writeData = atomicMemOpFunc(req.atomic_op, bramVec[i].read, atomicOpData[i], req.write_en);
            bramVec[i].put(req.write_en, atomicOpWordAddr[i], writeData);
            pendingReq[i][0] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: nonAtomicMemOp, rmw_write: True };
            atomicOpData[i] <= bramVec[i].read;
        endrule

        rule getRespFromCore( pendingReq[i][0] matches tagged Valid .req
                              &&& !isAtomicMemOp(req.atomic_op));
            pendingResp[i].enq(GenericAtomicMemResp{ write: req.write_en != 0, data: (req.rmw_write ? atomicOpData[i] : bramVec[i].read) });
            pendingReq[i][0] <= tagged Invalid;
        endrule

        ifc[i] = (interface GenericAtomicMemServerPort;
                    interface InputPort request;
                        method Action enq(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req) if (!isValid(pendingReq[i][1]));
                            let atomic_op = (req.write_en == 0) ? nonAtomicMemOp : req.atomic_op;
                            if (isAtomicMemOp(atomic_op)) begin
                                bramVec[i].put(0, req.word_addr, req.data);
                                atomicOpWordAddr[i] <= req.word_addr;
                                atomicOpData[i] <= req.data;
                            end else begin
                                bramVec[i].put(req.write_en, req.word_addr, req.data);
                            end
                            pendingReq[i][1] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: atomic_op, rmw_write: False };
                        endmethod
                        method Bool canEnq;
                            return !isValid(pendingReq[i][1]);
                        endmethod
                    endinterface
                    interface OutputPort response = toOutputPort(pendingResp[i]);
                endinterface);
    end

    return ifc;
endmodule

/// This function ignores the address of the request
function ActionValue#(GenericAtomicMemResp#(dataSz)) performGenericAtomicMemOpOnReg(Reg#(Bit#(dataSz)) r, GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req)
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz));
    return (actionvalue
            GenericAtomicMemResp#(dataSz) resp = GenericAtomicMemResp{ write: (req.write_en != 0), data: 0 };
            if (req.write_en == 0) begin
                resp.data = r;
            end else if ((req.write_en == '1) && (!isAtomicMemOp(req.atomic_op))) begin
                r <= req.data;
            end else if (!isAtomicMemOp(req.atomic_op)) begin
                r <= emulateWriteEn(r, req.data, req.write_en);
            end else begin
                let write_data = atomicMemOpFunc(req.atomic_op, r, req.data, req.write_en);
                r <= emulateWriteEn(r, write_data, req.write_en);
                resp.data = r;
            end
            return resp;
        endactionvalue);
endfunction

function ActionValue#(GenericAtomicMemResp#(dataSz)) performGenericAtomicMemOpOnRegs(Vector#(numRegs, Reg#(Bit#(dataSz))) regs, GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req)
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, TLog#(numRegs), wordAddrSz));
    return (actionvalue
            Bit#(TLog#(numRegs)) index = truncate(req.word_addr);
            GenericAtomicMemResp#(dataSz) resp = GenericAtomicMemResp{ write: (req.write_en != 0), data: 0 };
            if (index <= fromInteger(valueOf(numRegs) - 1)) begin
                resp <- performGenericAtomicMemOpOnReg(regs[index], req);
            end
            return resp;
        endactionvalue);
endfunction

function ActionValue#(GenericAtomicMemResp#(dataSz)) performGenericAtomicMemOpOnRegFile(RegFile#(Bit#(rfWordAddrSz), Bit#(dataSz)) rf, GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req)
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, rfWordAddrSz, wordAddrSz));
    return (actionvalue
            Bit#(rfWordAddrSz) index = truncate(req.word_addr);
            GenericAtomicMemResp#(dataSz) resp = GenericAtomicMemResp{ write: (req.write_en != 0), data: 0 };
            if (req.write_en == 0) begin
                resp.data = rf.sub(index);
            end else if ((req.write_en == '1) && (!isAtomicMemOp(req.atomic_op))) begin
                rf.upd(index, req.data);
            end else if (!isAtomicMemOp(req.atomic_op)) begin
                let new_data = emulateWriteEn(rf.sub(index), req.data, req.write_en);
                rf.upd(index, new_data);
            end else begin
                let old_data = rf.sub(index);
                let write_data = atomicMemOpFunc(req.atomic_op, old_data, req.data, req.write_en);
                let new_data = emulateWriteEn(old_data, write_data, req.write_en);
                rf.upd(index, new_data);
                resp.data = old_data;
            end
            return resp;
        endactionvalue);
endfunction

module mkGenericAtomicMemFromRegs#(Vector#(numRegs, Reg#(Bit#(dataSz))) regs)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, TLog#(numRegs), wordAddrSz),
                  Bits#(atomicMemOpT, atomicMemOpSz));
    FIFOG#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)) reqFIFO <- mkLFIFOG;
    FIFOG#(GenericAtomicMemResp#(dataSz)) respFIFO <- mkBypassFIFOG;
    rule performMemReq;
        let req = reqFIFO.first;
        reqFIFO.deq;
        let resp <- performGenericAtomicMemOpOnRegs(regs, req);
        respFIFO.enq(resp);
    endrule
    interface InputPort request = toInputPort(reqFIFO);
    interface OutputPort response = toOutputPort(respFIFO);
endmodule

module mkGenericAtomicMemFromRegFile#(RegFile#(Bit#(rfWordAddrSz), Bit#(dataSz)) rf)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, rfWordAddrSz, wordAddrSz),
                  Bits#(atomicMemOpT, atomicMemOpSz));
    FIFOG#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)) reqFIFO <- mkLFIFOG;
    FIFOG#(GenericAtomicMemResp#(dataSz)) respFIFO <- mkBypassFIFOG;
    rule performMemReq;
        let req = reqFIFO.first;
        reqFIFO.deq;
        let resp <- performGenericAtomicMemOpOnRegFile(rf, req);
        respFIFO.enq(resp);
    endrule
    interface InputPort request = toInputPort(reqFIFO);
    interface OutputPort response = toOutputPort(respFIFO);
endmodule

endpackage

// Copyright (c) 2017 Massachusetts Institute of Technology

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

/**
 * This package contains types, interfaces, and modules for a generic memory
 * type that supports atomic memory operations.
 *
 * The motivation behind this package is to give base memory implementations
 * that can be built upon to produce specialized memory interfaces.
 */
package GenericAtomicMem;

import BRAMCore::*;
import BuildVector::*;
import RegFile::*;
import Vector::*;

import Ehr::*;
import FIFOG::*;
import Port::*;

typedef struct {
    Bit#(writeEnSz) write_en;
    atomicMemOpT atomic_op;
    Bit#(wordAddrSz) word_addr;
    Bit#(dataSz) data;
} GenericAtomicMemReq#(numeric type writeEnSz, type atomicMemOpT, numeric type wordAddrSz, numeric type dataSz) deriving (Bits, Eq, FShow);

typedef struct {
    Bool write;
    Bit#(dataSz) data;
} GenericAtomicMemResp#(numeric type dataSz) deriving (Bits, Eq, FShow);

typedef ServerPort#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz), GenericAtomicMemResp#(dataSz))
        GenericAtomicMemServerPort#(numeric type writeEnSz, type atomicMemOpT, numeric type wordAddrSz, numeric type dataSz);

typedef ClientPort#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz), GenericAtomicMemResp#(dataSz))
        GenericAtomicMemClientPort#(numeric type writeEnSz, type atomicMemOpT, numeric type wordAddrSz, numeric type dataSz);

////////////////////////////////////////////////////////////////////////////////

// AtomicMemOp types, typeclasses, and instances

typeclass IsAtomicMemOp#(type atomicMemOpT);
    function atomicMemOpT nonAtomicMemOp;
    function Bool isAtomicMemOp(atomicMemOpT op);
endtypeclass

typeclass HasAtomicMemOpFunc#(type atomicMemOpT, numeric type dataSz, numeric type writeEnSz)
        provisos (IsAtomicMemOp#(atomicMemOpT));
    function Bit#(dataSz) atomicMemOpFunc(atomicMemOpT op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
endtypeclass

typedef void AMONone;

typedef enum {
    None,
    Swap
} AMOSwap deriving (Bits, Eq, FShow, Bounded);

typedef enum {
    None,
    Swap,
    And,
    Or,
    Xor
} AMOLogical deriving (Bits, Eq, FShow, Bounded);

typedef enum {
    None,
    Swap,
    And,
    Or,
    Xor,
    Add,
    Min,
    Max,
    Minu,
    Maxu
} AMOArithmetic deriving (Bits, Eq, FShow, Bounded);

/// This function extends byte enables into bit enables.
function Bit#(dataSz) writeEnExtend(Bit#(writeEnSz) write_en)
        provisos (Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz));
    Vector#(writeEnSz, Bit#(1)) write_en_vec = unpack(write_en);
    return pack(map(signExtend, write_en_vec));
endfunction

function Bit#(dataSz) emulateWriteEn(Bit#(dataSz) memData, Bit#(dataSz) writeData, Bit#(writeEnSz) writeEn)
        provisos (Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz));
    Bit#(dataSz) bitEn = writeEnExtend(writeEn);
    return (writeData & bitEn) | (memData & ~bitEn);
endfunction

instance IsAtomicMemOp#(AMONone);
    function AMONone nonAtomicMemOp = ?;
    function Bool isAtomicMemOp(AMONone op) = False;
endinstance
instance HasAtomicMemOpFunc#(AMONone, dataSz, writeEnSz);
    function Bit#(dataSz) atomicMemOpFunc(AMONone op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        return operandData;
    endfunction
endinstance

instance IsAtomicMemOp#(AMOSwap);
    function AMOSwap nonAtomicMemOp = None;
    function Bool isAtomicMemOp(AMOSwap op) = (op != None);
endinstance
instance HasAtomicMemOpFunc#(AMOSwap, dataSz, writeEnSz);
    function Bit#(dataSz) atomicMemOpFunc(AMOSwap op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        return operandData;
    endfunction
endinstance

instance IsAtomicMemOp#(AMOLogical);
    function AMOLogical nonAtomicMemOp = None;
    function Bool isAtomicMemOp(AMOLogical op) = (op != None);
endinstance
instance HasAtomicMemOpFunc#(AMOLogical, dataSz, writeEnSz);
    function Bit#(dataSz) atomicMemOpFunc(AMOLogical op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        return (case (op)
                    None: operandData;
                    Swap: operandData;
                    And:  (operandData & memData);
                    Or:   (operandData | memData);
                    Xor:  (operandData ^ memData);
                    default: operandData;
                endcase);
    endfunction
endinstance

instance IsAtomicMemOp#(AMOArithmetic);
    function AMOArithmetic nonAtomicMemOp = None;
    function Bool isAtomicMemOp(AMOArithmetic op) = (op != None);
endinstance
instance HasAtomicMemOpFunc#(AMOArithmetic, dataSz, writeEnSz)
        provisos(Mul#(writeEnSz, byteSz, dataSz),
                 Add#(a__, 1, dataSz),
                 Add#(b__, 1, byteSz));
    function Bit#(dataSz) atomicMemOpFunc(AMOArithmetic op, Bit#(dataSz) memData, Bit#(dataSz) operandData, Bit#(writeEnSz) writeEn);
        Bit#(dataSz) bitEn = writeEnExtend(writeEn);
        Vector#(writeEnSz, Bit#(byteSz)) memDataVec = unpack(memData);
        Vector#(writeEnSz, Bit#(byteSz)) operandDataVec = unpack(operandData);
        Bit#(1) memDataMSB = 0;
        Bit#(1) operandDataMSB = 0;
        Bool isSigned = ((op == Min) || (op == Max));
        for (Integer i = 0 ; i < valueOf(writeEnSz) ; i = i+1) begin
            if (writeEn[i] == 1) begin
                memDataMSB = msb(memDataVec[i]);
                operandDataMSB = msb(operandDataVec[i]);
            end
        end

        Bit#(dataSz) maskedMemData = (memData & bitEn) | (isSigned ? (signExtend(memDataMSB) & ~bitEn) : 0);
        Bit#(dataSz) maskedOperandData = (operandData & bitEn) | (isSigned ? (signExtend(operandDataMSB) & ~bitEn) : 0);

        Int#(TAdd#(1,dataSz)) memInt = unpack(isSigned ? signExtend(maskedMemData) : zeroExtend(maskedMemData));
        Int#(TAdd#(1,dataSz)) operandInt = unpack(isSigned ? signExtend(maskedOperandData) : zeroExtend(maskedOperandData));
        Bool operandDataLarger = operandInt > memInt;

        return (case (op)
                    None: operandData;
                    Swap: operandData;
                    And:  (operandData & memData);
                    Or:   (operandData | memData);
                    Xor:  (operandData ^ memData);
                    Add:  ((operandData & bitEn) + (memData & bitEn));
                    Min:  (operandDataLarger ? memData : operandData);
                    Max:  (operandDataLarger ? operandData : memData);
                    Minu: (operandDataLarger ? memData : operandData);
                    Maxu: (operandDataLarger ? operandData : memData);
                    default: operandData;
                endcase);
    endfunction
endinstance

////////////////////////////////////////////////////////////////////////////////

// Memory implementations

typedef struct {
    Bit#(writeEnSz) write_en;
    atomicMemOpT atomic_op;
    Bool rmw_write;
} GenericAtomicBRAMPendingReq#(numeric type writeEnSz, type atomicMemOpT) deriving (Bits, Eq, FShow);

/// This function is needed because BRAMCore does not support write enables
/// that are not 8 or 9 bits wide.
function BRAM_PORT_BE#(addrT, dataT, writeEnSz) to_BRAM_PORT_BE(BRAM_PORT#(addrT, dataT) bram);
    return (interface BRAM_PORT_BE;
                method Action put(Bit#(writeEnSz) writeen, addrT addr, dataT data);
                    bram.put(writeen != 0, addr, data);
                endmethod
                method dataT read = bram.read;
            endinterface);
endfunction

function BRAM_DUAL_PORT_BE#(addrT, dataT, writeEnSz) to_BRAM_DUAL_PORT_BE(BRAM_DUAL_PORT#(addrT, dataT) bram);
    return (interface BRAM_DUAL_PORT_BE;
                interface BRAM_PORT_BE a;
                    method Action put(Bit#(writeEnSz) writeen, addrT addr, dataT data);
                        bram.a.put(writeen != 0, addr, data);
                    endmethod
                    method dataT read = bram.a.read;
                endinterface
                interface BRAM_PORT_BE b;
                    method Action put(Bit#(writeEnSz) writeen, addrT addr, dataT data);
                        bram.b.put(writeen != 0, addr, data);
                    endmethod
                    method dataT read = bram.b.read;
                endinterface
            endinterface);
endfunction

/// This type matches the LoadFormat type in the Bluespec Reference Guide
typedef union tagged {
    void   None;
    String Hex;
    String Binary;
} LoadFormat deriving (Bits, Eq);

module mkGenericAtomicBRAM#(Integer numWords)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(TDiv#(dataSz, writeEnSz), writeEnSz, dataSz),
                  Bits#(atomicMemOpT, atomicMemOpSz));
    let _m <- mkGenericAtomicBRAMLoad(numWords, tagged None);
    return _m;
endmodule

module mkGenericAtomicBRAMLoad#(Integer numWords, LoadFormat loadFile)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(TDiv#(dataSz, writeEnSz), writeEnSz, dataSz), // This is needed for mkBRAMCore1BE
                  Bits#(atomicMemOpT, atomicMemOpSz));
    // If numWords == 0, then assume the entire address space is used
    Integer actualNumWords = numWords == 0 ? valueOf(TExp#(wordAddrSz)) : numWords;

    // Instantiate the BRAM
    BRAM_PORT_BE#(Bit#(wordAddrSz), Bit#(dataSz), writeEnSz) bram;
    if (valueOf(writeEnSz) == 1) begin
        BRAM_PORT#(Bit#(wordAddrSz), Bit#(dataSz)) bram_non_be;
        case (loadFile) matches
            tagged None: bram_non_be <- mkBRAMCore1(actualNumWords, False);
            tagged Hex .hexfile: bram_non_be <- mkBRAMCore1Load(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram_non_be <- mkBRAMCore1Load(actualNumWords, False, binfile, True);
        endcase
        bram = to_BRAM_PORT_BE(bram_non_be);
    end else begin
        case (loadFile) matches
            tagged None: bram <- mkBRAMCore1BE(actualNumWords, False);
            tagged Hex .hexfile: bram <- mkBRAMCore1BELoad(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram <- mkBRAMCore1BELoad(actualNumWords, False, binfile, True);
        endcase
    end

    Ehr#(2, Maybe#(GenericAtomicBRAMPendingReq#(writeEnSz, atomicMemOpT))) pendingReq <- mkEhr(tagged Invalid);
    FIFOG#(GenericAtomicMemResp#(dataSz)) pendingResp <- mkBypassFIFOG;
    Reg#(Bit#(wordAddrSz)) atomicOpWordAddr <- mkReg(0);
    Reg#(Bit#(dataSz)) atomicOpData <- mkReg(0);

    rule performAtomicMemoryOp( pendingReq[0] matches tagged Valid .req
                                &&& isAtomicMemOp(req.atomic_op));
        let writeData = atomicMemOpFunc(req.atomic_op, bram.read, atomicOpData, req.write_en);
        bram.put(req.write_en, atomicOpWordAddr, writeData);
        pendingReq[0] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: nonAtomicMemOp, rmw_write: True };
        atomicOpData <= bram.read;
    endrule

    rule getRespFromCore( pendingReq[0] matches tagged Valid .req
                          &&& !isAtomicMemOp(req.atomic_op));
        pendingResp.enq(GenericAtomicMemResp{ write: req.write_en != 0, data: (req.rmw_write ? atomicOpData : bram.read) });
        pendingReq[0] <= tagged Invalid;
    endrule

    interface InputPort request;
        method Action enq(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req) if (!isValid(pendingReq[1]));
            let atomic_op = (req.write_en == 0) ? nonAtomicMemOp : req.atomic_op;
            if (isAtomicMemOp(atomic_op)) begin
                bram.put(0, req.word_addr, req.data);
                atomicOpWordAddr <= req.word_addr;
                atomicOpData <= req.data;
            end else begin
                bram.put(req.write_en, req.word_addr, req.data);
            end
            pendingReq[1] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: atomic_op, rmw_write: False };
        endmethod
        method Bool canEnq;
            return !isValid(pendingReq[1]);
        endmethod
    endinterface
    interface OutputPort response = toOutputPort(pendingResp);
endmodule

module mkGenericAtomicBRAMLoad2Port#(Integer numWords, LoadFormat loadFile)(Vector#(2, GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(TDiv#(dataSz, writeEnSz), writeEnSz, dataSz), // This is needed for mkBRAMCore1BE
                  Bits#(atomicMemOpT, atomicMemOpSz));
    // If numWords == 0, then assume the entire address space is used
    Integer actualNumWords = numWords == 0 ? valueOf(TExp#(wordAddrSz)) : numWords;

    // Instantiate the BRAM
    BRAM_DUAL_PORT_BE#(Bit#(wordAddrSz), Bit#(dataSz), writeEnSz) bram;
    if (valueOf(writeEnSz) == 1) begin
        BRAM_DUAL_PORT#(Bit#(wordAddrSz), Bit#(dataSz)) bram_non_be;
        case (loadFile) matches
            tagged None: bram_non_be <- mkBRAMCore2(actualNumWords, False);
            tagged Hex .hexfile: bram_non_be <- mkBRAMCore2Load(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram_non_be <- mkBRAMCore2Load(actualNumWords, False, binfile, True);
        endcase
        bram = to_BRAM_DUAL_PORT_BE(bram_non_be);
    end else begin
        case (loadFile) matches
            tagged None: bram <- mkBRAMCore2BE(actualNumWords, False);
            tagged Hex .hexfile: bram <- mkBRAMCore2BELoad(actualNumWords, False, hexfile, False);
            tagged Binary .binfile: bram <- mkBRAMCore2BELoad(actualNumWords, False, binfile, True);
        endcase
    end

    Vector#(2, BRAM_PORT_BE#(Bit#(wordAddrSz), Bit#(dataSz), writeEnSz)) bramVec = vec(bram.a, bram.b);
    Vector#(2, Ehr#(2, Maybe#(GenericAtomicBRAMPendingReq#(writeEnSz, atomicMemOpT)))) pendingReq <- replicateM(mkEhr(tagged Invalid));
    Vector#(2, FIFOG#(GenericAtomicMemResp#(dataSz))) pendingResp <- replicateM(mkBypassFIFOG);
    Vector#(2, Reg#(Bit#(wordAddrSz))) atomicOpWordAddr <- replicateM(mkReg(0));
    Vector#(2, Reg#(Bit#(dataSz))) atomicOpData <- replicateM(mkReg(0));

    Vector#(2, GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)) ifc;

    for (Integer i = 0 ; i < 2 ; i = i+1) begin
        rule performAtomicMemoryOp( pendingReq[i][0] matches tagged Valid .req
                                    &&& isAtomicMemOp(req.atomic_op));
            let writeData = atomicMemOpFunc(req.atomic_op, bramVec[i].read, atomicOpData[i], req.write_en);
            bramVec[i].put(req.write_en, atomicOpWordAddr[i], writeData);
            pendingReq[i][0] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: nonAtomicMemOp, rmw_write: True };
            atomicOpData[i] <= bramVec[i].read;
        endrule

        rule getRespFromCore( pendingReq[i][0] matches tagged Valid .req
                              &&& !isAtomicMemOp(req.atomic_op));
            pendingResp[i].enq(GenericAtomicMemResp{ write: req.write_en != 0, data: (req.rmw_write ? atomicOpData[i] : bramVec[i].read) });
            pendingReq[i][0] <= tagged Invalid;
        endrule

        ifc[i] = (interface GenericAtomicMemServerPort;
                    interface InputPort request;
                        method Action enq(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req) if (!isValid(pendingReq[i][1]));
                            let atomic_op = (req.write_en == 0) ? nonAtomicMemOp : req.atomic_op;
                            if (isAtomicMemOp(atomic_op)) begin
                                bramVec[i].put(0, req.word_addr, req.data);
                                atomicOpWordAddr[i] <= req.word_addr;
                                atomicOpData[i] <= req.data;
                            end else begin
                                bramVec[i].put(req.write_en, req.word_addr, req.data);
                            end
                            pendingReq[i][1] <= tagged Valid GenericAtomicBRAMPendingReq{ write_en: req.write_en, atomic_op: atomic_op, rmw_write: False };
                        endmethod
                        method Bool canEnq;
                            return !isValid(pendingReq[i][1]);
                        endmethod
                    endinterface
                    interface OutputPort response = toOutputPort(pendingResp[i]);
                endinterface);
    end

    return ifc;
endmodule

function ActionValue#(GenericAtomicMemResp#(dataSz)) performGenericAtomicMemOpOnRegs(Vector#(numRegs, Reg#(Bit#(dataSz))) regs, GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req)
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, TLog#(numRegs), wordAddrSz));
    return (actionvalue
            Bit#(TLog#(numRegs)) index = truncate(req.word_addr);
            GenericAtomicMemResp#(dataSz) resp = GenericAtomicMemResp{ write: (req.write_en != 0), data: 0 };
            if (index <= fromInteger(valueOf(numRegs) - 1)) begin
                if (req.write_en == 0) begin
                    resp.data = regs[index];
                end else if ((req.write_en == '1) && (!isAtomicMemOp(req.atomic_op))) begin
                    regs[index] <= req.data;
                end else if (!isAtomicMemOp(req.atomic_op)) begin
                    regs[index] <= emulateWriteEn(regs[index], req.data, req.write_en);
                end else begin
                    let write_data = atomicMemOpFunc(req.atomic_op, regs[index], req.data, req.write_en);
                    regs[index] <= emulateWriteEn(regs[index], write_data, req.write_en);
                    resp.data = regs[index];
                end
            end
            return resp;
        endactionvalue);
endfunction

function ActionValue#(GenericAtomicMemResp#(dataSz)) performGenericAtomicMemOpOnRegFile(RegFile#(Bit#(rfWordAddrSz), Bit#(dataSz)) rf, GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz) req)
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, rfWordAddrSz, wordAddrSz));
    return (actionvalue
            Bit#(rfWordAddrSz) index = truncate(req.word_addr);
            GenericAtomicMemResp#(dataSz) resp = GenericAtomicMemResp{ write: (req.write_en != 0), data: 0 };
            if (req.write_en == 0) begin
                resp.data = rf.sub(index);
            end else if ((req.write_en == '1) && (!isAtomicMemOp(req.atomic_op))) begin
                rf.upd(index, req.data);
            end else if (!isAtomicMemOp(req.atomic_op)) begin
                let new_data = emulateWriteEn(rf.sub(index), req.data, req.write_en);
                rf.upd(index, new_data);
            end else begin
                let old_data = rf.sub(index);
                let write_data = atomicMemOpFunc(req.atomic_op, old_data, req.data, req.write_en);
                let new_data = emulateWriteEn(old_data, write_data, req.write_en);
                rf.upd(index, new_data);
                resp.data = old_data;
            end
            return resp;
        endactionvalue);
endfunction

module mkGenericAtomicMemFromRegs#(Vector#(numRegs, Reg#(Bit#(dataSz))) regs)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, TLog#(numRegs), wordAddrSz),
                  Bits#(atomicMemOpT, atomicMemOpSz));
    FIFOG#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)) reqFIFO <- mkLFIFOG;
    FIFOG#(GenericAtomicMemResp#(dataSz)) respFIFO <- mkBypassFIFOG;
    rule performMemReq;
        let req = reqFIFO.first;
        reqFIFO.deq;
        let resp <- performGenericAtomicMemOpOnRegs(regs, req);
        respFIFO.enq(resp);
    endrule
    interface InputPort request = toInputPort(reqFIFO);
    interface OutputPort response = toOutputPort(respFIFO);
endmodule

module mkGenericAtomicMemFromRegFile#(RegFile#(Bit#(rfWordAddrSz), Bit#(dataSz)) rf)(GenericAtomicMemServerPort#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz))
        provisos (HasAtomicMemOpFunc#(atomicMemOpT, dataSz, writeEnSz),
                  Mul#(writeEnSz, byteSz, dataSz),
                  Add#(a__, 1, byteSz),
                  Add#(b__, rfWordAddrSz, wordAddrSz),
                  Bits#(atomicMemOpT, atomicMemOpSz));
    FIFOG#(GenericAtomicMemReq#(writeEnSz, atomicMemOpT, wordAddrSz, dataSz)) reqFIFO <- mkLFIFOG;
    FIFOG#(GenericAtomicMemResp#(dataSz)) respFIFO <- mkBypassFIFOG;
    rule performMemReq;
        let req = reqFIFO.first;
        reqFIFO.deq;
        let resp <- performGenericAtomicMemOpOnRegFile(rf, req);
        respFIFO.enq(resp);
    endrule
    interface InputPort request = toInputPort(reqFIFO);
    interface OutputPort response = toOutputPort(respFIFO);
endmodule

endpackage


minor changes

minor changes

// bsv libraries
//import SpecialFIFOs::*;
//import Vector::*;
//import StmtFSM::*;
//import FIFO::*;
//import Connectable::*;
import GetPut::*;

// portz libraries
import AxiMasterSlave::*;
//import Directory::*;
import CtrlMux::*;
//import Portal::*;
import Leds::*;
import Top::*;
import PPS7::*;
import PS7::*;

interface EchoPins#(numeric type gpio_width, numeric type mio_width);
    interface Pps7Ddr#(4, 32, 4, 32, 64, 12, 54) ddr;
    interface Inout#(Bit#(mio_width))       mio;
    interface Pps7Ps#(4, 32, 4, 32, 64, 12, 54) ps;
    interface LEDS                          leds;
endinterface

module mkZynqTop(EchoPins#(64/*gpio_width*/, 54));
    let axiTop <- mkAxiTop();
    let data_width = 32;
    let id_width = 12;
    PS7#(4, 32, 4, 32/*data_width*/, 64/*gpio_width*/, 12/*id_width*/, 54) ps7 <- mkPS7(4, 32/*data_width*/, 4, 32, 64/*gpio_width*/, 12/*id_width*/, 54);

    Bool intval <- axiTop.interrupt();
    //Bit#(1) intval <- axiTop.interrupt ? 1'b1 : 1'b0;
    ps7.irq.f2p({15'b0, pack(intval)});
    let fclock0 <- ps7.fclk.clk0();
    ps7.m_axi_gp[0].aclk(fclock0);
    //ps7.s_axi_hp[0].axi.aclk(fclock0);
    //ps7.fclk_reset[0].n = ?;

    rule m_ar_rule; //.M_AXI_GP0_ARREADY(ctrl_arready), .M_AXI_GP0_ARVALID(ctrl_arvalid),
        let m_ar <- ps7.m_axi_gp[0].req_ar.get();
            //m_ar.lock; //m_ar.qos;
        axiTop.ctrl.read.readAddr(m_ar.addr, m_ar.len, m_ar.size, m_ar.burst, m_ar.prot, m_ar.cache, m_ar.id);
    endrule

    rule m_aw_rule; //.M_AXI_GP0_AWREADY(ctrl_awready), .M_AXI_GP0_AWVALID(ctrl_awvalid),
        let m_aw <- ps7.m_axi_gp[0].req_aw.get();
            //m_aw.lock; //m_aw.qos;
        axiTop.ctrl.write.writeAddr(m_aw.addr, m_aw.len, m_aw.size, m_aw.burst, m_aw.prot, m_aw.cache, m_aw.id);
    endrule

    rule m_arespb_rule; //.M_AXI_GP0_BREADY(ctrl_bready), .M_AXI_GP0_BVALID(ctrl_bvalid),
        AxiRESP#(12/*id_width*/) m_arespb;
        m_arespb.id <- axiTop.ctrl.write.bid();
        m_arespb.resp <- axiTop.ctrl.write.writeResponse();
        ps7.m_axi_gp[0].resp_b.put(m_arespb);
    endrule

    rule m_arespr_rule; //.M_AXI_GP0_RREADY(ctrl_rready), .M_AXI_GP0_RVALID(ctrl_rvalid),
        AxiRead#(32/*data_width*/, 12/*id_width*/) m_arespr;
        m_arespr.r.id = axiTop.ctrl.read.rid();
        m_arespr.r.resp = 2'b0; //.M_AXI_GP0_RRESP(ctrl_rresp),
        m_arespr.rd.data <- axiTop.ctrl.read.readData();
        m_arespr.rd.last = axiTop.ctrl.read.last();
        ps7.m_axi_gp[0].resp_read.put(m_arespr);
    endrule

    rule m_arespw_rule; //.M_AXI_GP0_WREADY(ctrl_wready), .M_AXI_GP0_WVALID(ctrl_wvalid),
        let m_arespw <- ps7.m_axi_gp[0].resp_write.get();
        axiTop.ctrl.write.writeData(m_arespw.wd.data, m_arespw.wstrb, m_arespw.wd.last, m_arespw.wid);
    endrule

/* m_axi interface not bound in examples/echo/Top.bsv
    rule s_areqr_rule; //.S_AXI_HP0_ARREADY(m_axi_arready), .S_AXI_HP0_ARVALID(m_axi_arvalid),
        AxiREQ#(12/*id_width* /) s_areqr;
        s_areqr.lock = 0;
        s_areqr.qos = 0;
        s_areqr.addr = axiTop.m_axi.read.readAddr();
        s_areqr.burst = axiTop.m_axi.read.readBurstType();
        s_areqr.cache = axiTop.m_axi.read.readBurstCache();
        s_areqr.id = axiTop.m_axi.read.readId();
        s_areqr.len = axiTop.m_axi.read.readBurstLen();
        s_areqr.prot = axiTop.m_axi.read.readBurstProt();
        s_areqr.size = axiTop.m_axi.read.readBurstWidth();
        ps7.s_axi_hp[0].axi.req_ar.put(s_areqr);
    endrule

    rule s_areqw_rule; //.S_AXI_HP0_AWREADY(m_axi_awready), .S_AXI_HP0_AWVALID(m_axi_awvalid),
        AxiREQ#(12/*id_width* /) s_areqw;
        s_areqw.lock = 0;
        s_areqw.qos = 0;
        s_areqw.addr = axiTop.m_axi.write.writeAddr();
        s_areqw.burst = axiTop.m_axi.write.writeBurstType();
        s_areqw.cache = axiTop.m_axi.write.writeBurstCache();
        s_areqw.id = axiTop.m_axi.write.writeId();
        s_areqw.len = axiTop.m_axi.write.writeBurstLen();
        s_areqw.prot = axiTop.m_axi.write.writeBurstProt();
        s_areqw.size = axiTop.m_axi.write.writeBurstWidth();
        ps7.s_axi_hp[0].axi.req_ar.put(s_areqr);
    endrule

    rule s_arespb_rule; //.S_AXI_HP0_BREADY(m_axi_bready), .S_AXI_HP0_BVALID(m_axi_bvalid),
        let s_arespb = ps7.s_axi_hp[0].axi.resp_b.get();
        axiTop.m_axi.write.writeResponse(s_arespb.resp, s_arespb.id);
    endrule

    rule s_arespr_rule; //.S_AXI_HP0_RREADY(m_axi_rready), .S_AXI_HP0_RVALID(m_axi_rvalid),
        let s_arespr = ps7.s_axi_hp[0].axi.resp_read.get();
        axiTop.m_axi.read.readData(s_arespr.rd.data, s_arespr.r.resp, s_arespr.rd.last, s_arespr.r.id);
    endrule

    rule s_arespw_rule; //.S_AXI_HP0_WREADY(m_axi_wready), .S_AXI_HP0_WVALID(m_axi_wvalid),
        AxiWrite#(32/*data_width* /, 12/*id_width* /) s_arespw;
        s_arespw.wid = axiTop.m_axi.write.writeWid();
        //??s_arespw.wd.data <= axiTop.m_axi.write.writeWid(); //.m_axi_write_writeData(m_axi_wdata_wire),
        //.S_AXI_HP0_WDATA(m_axi_wdata),
        s_arespw.wd.last = axiTop.m_axi.write.writeLastDataBeat();
        s_arespw.wstrb = axiTop.m_axi.write.writeDataByteEnable();
        ps7.s_axi_hp[0].axi.resp_write.put(s_arespw);
    endrule
end of m_axi */

    interface Pps7Ddr ddr = ps7.ddr;
    interface Inout   mio = ps7.mio;
    interface Pps7Ps  ps = ps7.ps;
    interface LEDS    leds = axiTop.leds;
endmodule : mkZynqTop

// bsv libraries
//import SpecialFIFOs::*;
//import Vector::*;
//import StmtFSM::*;
//import FIFO::*;
//import Connectable::*;
import GetPut::*;

// portz libraries
import AxiMasterSlave::*;
//import Directory::*;
//import CtrlMux::*;
//import Portal::*;
import Leds::*;
import Top::*;
import PPS7::*;
import PS7::*;

interface EchoPins#(numeric type gpio_width, numeric type mio_width);
    interface Pps7Ddr#(4, 32, 4, 32, 64, 12, 54) ddr;
    interface Inout#(Bit#(mio_width))       mio;
    interface Pps7Ps#(4, 32, 4, 32, 64, 12, 54) ps;
    interface LEDS                          leds;
endinterface

module mkZynqTop(EchoPins#(64/*gpio_width*/, 54));
    let axiTop <- mkAxiTop();
    let data_width = 32;
    let id_width = 12;
    PS7#(4, 32, 4, 32/*data_width*/, 64/*gpio_width*/, 12/*id_width*/, 54) ps7 <- mkPS7(4, 32/*data_width*/, 4, 32, 64/*gpio_width*/, 12/*id_width*/, 54);

    Bit#(1) intval <- pack(axiTop.interrupt);
    //Bit#(1) intval <- axiTop.interrupt ? 1'b1 : 1'b0;
    ps7.irq.f2p({15'b0, pack(intval)});
    let fclock0 <- ps7.fclk.clk0();
    ps7.m_axi_gp[0].aclk(fclock0);
    //ps7.s_axi_hp[0].axi.aclk(fclock0);
    //ps7.fclk_reset[0].n = ?;

    rule m_ar_rule; //.M_AXI_GP0_ARREADY(ctrl_arready), .M_AXI_GP0_ARVALID(ctrl_arvalid),
        let m_ar <- ps7.m_axi_gp[0].req_ar.get();
            //m_ar.lock; //m_ar.qos;
        axiTop.ctrl.read.readAddr(m_ar.addr, m_ar.len, m_ar.size, m_ar.burst, m_ar.prot, m_ar.cache, m_ar.id);
    endrule

    rule m_aw_rule; //.M_AXI_GP0_AWREADY(ctrl_awready), .M_AXI_GP0_AWVALID(ctrl_awvalid),
        let m_aw <- ps7.m_axi_gp[0].req_aw.get();
            //m_aw.lock; //m_aw.qos;
        axiTop.ctrl.write.writeAddr(m_aw.addr, m_aw.len, m_aw.size, m_aw.burst, m_aw.prot, m_aw.cache, m_aw.id);
    endrule

    rule m_arespb_rule; //.M_AXI_GP0_BREADY(ctrl_bready), .M_AXI_GP0_BVALID(ctrl_bvalid),
        AxiRESP#(12/*id_width*/) m_arespb;
        m_arespb.id <- axiTop.ctrl.write.bid();
        m_arespb.resp <- axiTop.ctrl.write.writeResponse();
        ps7.m_axi_gp[0].resp_b.put(m_arespb);
    endrule

    rule m_arespr_rule; //.M_AXI_GP0_RREADY(ctrl_rready), .M_AXI_GP0_RVALID(ctrl_rvalid),
        AxiRead#(32/*data_width*/, 12/*id_width*/) m_arespr;
        m_arespr.r.id = axiTop.ctrl.read.rid();
        m_arespr.r.resp = 2'b0; //.M_AXI_GP0_RRESP(ctrl_rresp),
        m_arespr.rd.data <- axiTop.ctrl.read.readData();
        m_arespr.rd.last = axiTop.ctrl.read.last();
        ps7.m_axi_gp[0].resp_read.put(m_arespr);
    endrule

    rule m_arespw_rule; //.M_AXI_GP0_WREADY(ctrl_wready), .M_AXI_GP0_WVALID(ctrl_wvalid),
        let m_arespw <- ps7.m_axi_gp[0].resp_write.get();
        axiTop.ctrl.write.writeData(m_arespw.wd.data, m_arespw.wstrb, m_arespw.wd.last, m_arespw.wid);
    endrule

/* m_axi interface not bound in examples/echo/Top.bsv
    rule s_areqr_rule; //.S_AXI_HP0_ARREADY(m_axi_arready), .S_AXI_HP0_ARVALID(m_axi_arvalid),
        AxiREQ#(12/*id_width* /) s_areqr;
        s_areqr.lock = 0;
        s_areqr.qos = 0;
        s_areqr.addr = axiTop.m_axi.read.readAddr();
        s_areqr.burst = axiTop.m_axi.read.readBurstType();
        s_areqr.cache = axiTop.m_axi.read.readBurstCache();
        s_areqr.id = axiTop.m_axi.read.readId();
        s_areqr.len = axiTop.m_axi.read.readBurstLen();
        s_areqr.prot = axiTop.m_axi.read.readBurstProt();
        s_areqr.size = axiTop.m_axi.read.readBurstWidth();
        ps7.s_axi_hp[0].axi.req_ar.put(s_areqr);
    endrule

    rule s_areqw_rule; //.S_AXI_HP0_AWREADY(m_axi_awready), .S_AXI_HP0_AWVALID(m_axi_awvalid),
        AxiREQ#(12/*id_width* /) s_areqw;
        s_areqw.lock = 0;
        s_areqw.qos = 0;
        s_areqw.addr = axiTop.m_axi.write.writeAddr();
        s_areqw.burst = axiTop.m_axi.write.writeBurstType();
        s_areqw.cache = axiTop.m_axi.write.writeBurstCache();
        s_areqw.id = axiTop.m_axi.write.writeId();
        s_areqw.len = axiTop.m_axi.write.writeBurstLen();
        s_areqw.prot = axiTop.m_axi.write.writeBurstProt();
        s_areqw.size = axiTop.m_axi.write.writeBurstWidth();
        ps7.s_axi_hp[0].axi.req_ar.put(s_areqr);
    endrule

    rule s_arespb_rule; //.S_AXI_HP0_BREADY(m_axi_bready), .S_AXI_HP0_BVALID(m_axi_bvalid),
        let s_arespb = ps7.s_axi_hp[0].axi.resp_b.get();
        axiTop.m_axi.write.writeResponse(s_arespb.resp, s_arespb.id);
    endrule

    rule s_arespr_rule; //.S_AXI_HP0_RREADY(m_axi_rready), .S_AXI_HP0_RVALID(m_axi_rvalid),
        let s_arespr = ps7.s_axi_hp[0].axi.resp_read.get();
        axiTop.m_axi.read.readData(s_arespr.rd.data, s_arespr.r.resp, s_arespr.rd.last, s_arespr.r.id);
    endrule

    rule s_arespw_rule; //.S_AXI_HP0_WREADY(m_axi_wready), .S_AXI_HP0_WVALID(m_axi_wvalid),
        AxiWrite#(32/*data_width* /, 12/*id_width* /) s_arespw;
        s_arespw.wid = axiTop.m_axi.write.writeWid();
        //??s_arespw.wd.data <= axiTop.m_axi.write.writeWid(); //.m_axi_write_writeData(m_axi_wdata_wire),
        //.S_AXI_HP0_WDATA(m_axi_wdata),
        s_arespw.wd.last = axiTop.m_axi.write.writeLastDataBeat();
        s_arespw.wstrb = axiTop.m_axi.write.writeDataByteEnable();
        ps7.s_axi_hp[0].axi.resp_write.put(s_arespw);
    endrule
end of m_axi */

    interface Pps7Ddr ddr = ps7.ddr;
    interface Inout   mio = ps7.mio;
    interface Pps7Ps  ps = ps7.ps;
    interface LEDS    leds = axiTop.leds;
endmodule : mkZynqTop