use ConnectalBram::BRAM2Server

use ConnectalBram::BRAM2Server

// Copyright (c) 2015 Cornell University.

// 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 Arith::*;
import BRAM::*;
import BRAMCore::*;
import Connectable::*;
import ConnectalBram::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import OInt::*;
import StmtFSM::*;
import Vector::*;
import Pipe::*;
import AsymmetricBRAM::*;

import BcamTypes::*;

typedef struct {
   Bit#(9) wPatt;
   Bit#(4) wIndx;
   Bit#(16) wIndc; // sqrt(256)
   Bit#(4) wAddr_indx; // log(depth)/2
   Bit#(4) wAddr_indc; // log(depth)/2
   Bit#(1) wIVld;
   Bit#(1) wEnb_iVld;
   Bit#(1) wEnb_indx;
   Bit#(1) wEnb_indc;
} Ram9bWriteRequest deriving (Bits, Eq);

typedef struct {
   Bit#(9) mPatt;
} Ram9bReadRequest deriving (Bits, Eq);

typedef struct {
   Bit#(256) mIndc;
} Ram9bReadResponse deriving (Bits, Eq);

interface Ram9bx256;
   interface Put#(Ram9bWriteRequest) writeReq;
   interface Put#(Ram9bReadRequest) readReq;
   interface Get#(Ram9bReadResponse) readResp;
endinterface
module mkRam9bx256(Ram9bx256);
   let verbose = False;
   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule every1 if (verbose);
      cycle <= cycle + 1;
   endrule

   FIFO#(Bit#(16)) iVld_fifo <- mkFIFO;
   FIFO#(Bit#(256)) mIndc_fifo <- mkFIFO;

   // WWID = 1, RWID = 32, WDEP = 16384, OREG = 1, INIT = 1
`define VLDRAM AsymmetricBRAM#(Bit#(9), Bit#(16), Bit#(13), Bit#(1))
   `VLDRAM vldram <- mkAsymmetricBRAM(True, False, "VLDram");

   // WWID = 5, RWID = 40, WDEP = 4096, OREG = 0, INIT = 1
`define INDXRAM AsymmetricBRAM#(Bit#(9), Bit#(16), Bit#(11), Bit#(4))
   Vector#(4, `INDXRAM) indxram <- replicateM(mkAsymmetricBRAM(True, False, "indxRam"));

   // DWID = 32, DDEP = 32, MRDW = "DONT_CARE", RREG=ALL, INIT=1
   BRAM_Configure bramCfg = defaultValue;
   bramCfg.memorySize = 16;
   bramCfg.latency=2;
   Vector#(16, BRAM2Port#(Bit#(4), Bit#(16))) dpmlab <- replicateM(ConnectalBram::mkBRAM2Server(bramCfg));

   rule vldram_output;
      let v <- vldram.readServer.response.get;
      if (verbose) $display("vldram %d: read iVld_fifo.enq=%x", cycle, v);
      iVld_fifo.enq(v);
   endrule

   for (Integer i=0; i<4; i=i+1) begin
      rule indxram_output;
         let v <- indxram[i].readServer.response.get;
         if (verbose) $display("indxram: read response=%x", v);
         for (Integer j=0; j<4; j=j+1) begin
            Bit#(4) addr = v[(j+1)*4-1 : j*4];
            dpmlab[i*4+j].portB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: addr, datain: ?});
            if (verbose) $display("dpmlab %d: read i=%d, j=%d index=%d addr=%x", cycle, i, j, i*4+j, addr);
         end
      endrule
   end

   rule dpmlab_read_response;
      let ivld <- toGet(iVld_fifo).get;
      Bit#(256) mIndc = 0;
      for (Integer i=0; i<4; i=i+1) begin
         for (Integer j=0; j<4; j=j+1) begin
            let v <- dpmlab[i*4+j].portB.response.get;
            Vector#(16, Bit#(1)) ivld_vec = replicate(ivld[4*i+j]);
            Bit#(16) mIndcV = v & pack(ivld_vec);
            mIndc[(i*4+j+1)*16-1 : (i*4+j)*16] = mIndcV;
            if (verbose) $display("dpmlab %d: read i=%d, j=%d index=%d v=%x", cycle, i, j, i*4+j, v);
         end
      end
      mIndc_fifo.enq(mIndc);
      if (verbose) $display("dpmlab %d: mIndc=%x", cycle, pack(mIndc));
   endrule

   interface Put writeReq;
      method Action put(Ram9bWriteRequest req);
         let wIVld  = req.wIVld;
         let wEnb_iVld = req.wEnb_iVld;
         let wEnb_indx = req.wEnb_indx;
         if (wEnb_iVld == 1) begin
            Bit#(13) wAddr = {req.wPatt, req.wAddr_indx};
            vldram.writeServer.put(tuple2(wAddr, pack(wIVld)));
            if (verbose) $display("vldram %d: write to vldram wAddr=%x, data=%x", cycle, wAddr, pack(wIVld));
         end

         if (wEnb_indx == 1) begin
            for (Integer i=0; i<4; i=i+1) begin
               if (req.wAddr_indx[3:2] == fromInteger(i)) begin
                  Bit#(11) wAddr = {req.wPatt, req.wAddr_indx[1:0]};
                  indxram[i].writeServer.put(tuple2(wAddr, req.wIndx));
                  if (verbose) $display("indxram %d: write i=%x wAddr=%x, wIndx=%x", cycle, i, wAddr, req.wIndx);
               end
            end
         end

         let wAddr_indc = req.wAddr_indc;
         let wIndc = req.wIndc;
         let wEnb_indc = req.wEnb_indc;
         if (wEnb_indc == 1) begin
            for (Integer i=0; i<4; i=i+1) begin
               for (Integer j=0; j<4; j=j+1) begin
                  if ((req.wAddr_indx[3:2] == fromInteger(i)) && req.wAddr_indx[1:0] == fromInteger(j)) begin
                     if (verbose) $display("dpmlab %d: write i=%d, j=%d index=%d, addr=%x, wIndc=%x", cycle, i, j, i*4+j, wAddr_indc, wIndc);
                     dpmlab[i*4+j].portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address: wAddr_indc, datain: wIndc});
                  end
               end
            end
         end
      endmethod
   endinterface
   interface Put readReq;
      method Action put(Ram9bReadRequest req);
         let mPatt = req.mPatt;
         vldram.readServer.request.put(mPatt);
         for (Integer i=0; i<4; i=i+1) begin
            indxram[i].readServer.request.put(mPatt);
            if (verbose) $display("indxram: read patt=%x", mPatt);
         end
      endmethod
   endinterface
   interface Get readResp;
      method ActionValue#(Ram9bReadResponse) get();
         let _mIndc <- toGet(mIndc_fifo).get;
         return Ram9bReadResponse{mIndc: _mIndc};
      endmethod
   endinterface
endmodule

typedef struct {
   Bit#(9) wPatt;
   Bit#(4) wIndx;
   Bit#(16) wIndc; // sqrt(256)
   Bit#(TAdd#(TLog#(cdep), 4)) wAddr_indx; // log(depth)/2
   Bit#(4) wAddr_indc; // log(depth)/2
   Bit#(1) wIVld;
   Bit#(1) wEnb_iVld;
   Bit#(1) wEnb_indx;
   Bit#(1) wEnb_indc;
} WriteRequest#(numeric type cdep) deriving (Bits, Eq);

typedef struct {
   Bit#(9) mPatt;
} ReadRequest deriving (Bits, Eq);

typedef struct {
   Bit#(TMul#(cdep, 256)) mIndc;
} ReadResponse#(numeric type cdep) deriving (Bits, Eq);

interface Ram9b#(numeric type cdep);
   interface Put#(WriteRequest#(cdep)) writeRequest;
   interface Put#(ReadRequest) readRequest;
   interface Get#(ReadResponse#(cdep)) readResponse;
endinterface
module mkRam9b(Ram9b#(cdep));

   let verbose = False;
   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule every1 if (verbose);
      cycle <= cycle + 1;
   endrule

   Vector#(cdep, Ram9bx256) ram <- replicateM(mkRam9bx256());

   interface Put writeRequest;
      method Action put(WriteRequest#(cdep) req);
         Vector#(cdep, Bool) wEnb = replicate(False);
         Vector#(cdep, Ram9bWriteRequest) requests;
         for (Integer i=0; i < valueOf(cdep); i=i+1) begin
            wEnb[i] = ((req.wAddr_indx >> 4) == fromInteger(i));
            requests[i] = Ram9bWriteRequest { wPatt: req.wPatt,
               wIndx: req.wIndx,
               wIndc: req.wIndc,
               wAddr_indx: req.wAddr_indx[3:0],
               wAddr_indc: req.wAddr_indc,
               wIVld: req.wIVld,
               wEnb_iVld: pack(unpack(req.wEnb_iVld) && wEnb[i]),
               wEnb_indx: pack(unpack(req.wEnb_indx) && wEnb[i]),
               wEnb_indc: pack(unpack(req.wEnb_indc) && wEnb[i])
            };
            ram[i].writeReq.put(requests[i]);
         end
      endmethod
   endinterface
   interface Put readRequest;
      method Action put (ReadRequest req);
         Vector#(cdep, Ram9bReadRequest) requests;
         for (Integer i=0; i < valueOf(cdep); i=i+1) begin
            requests[i] = Ram9bReadRequest{mPatt: req.mPatt};
            ram[i].readReq.put(requests[i]);
         end
         if (verbose) $display("ram9b %d: mPatt=%x", cycle, req.mPatt);
      endmethod
   endinterface
   interface Get readResponse;
      method ActionValue#(ReadResponse#(cdep)) get();
         Vector#(cdep, Bit#(256)) _mIndc;
         for (Integer i=0; i < valueOf(cdep); i=i+1) begin
            let v <- toGet(ram[i].readResp).get;
            _mIndc[i] = v.mIndc;
         end
         return ReadResponse{mIndc: pack(_mIndc)};
      endmethod
   endinterface
endmodule

// Copyright (c) 2015 Cornell University.

// 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 Arith::*;
import BRAM::*;
import BRAMCore::*;
import Connectable::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import OInt::*;
import StmtFSM::*;
import Vector::*;
import Pipe::*;
import AsymmetricBRAM::*;

import BcamTypes::*;

typedef struct {
   Bit#(9) wPatt;
   Bit#(4) wIndx;
   Bit#(16) wIndc; // sqrt(256)
   Bit#(4) wAddr_indx; // log(depth)/2
   Bit#(4) wAddr_indc; // log(depth)/2
   Bit#(1) wIVld;
   Bit#(1) wEnb_iVld;
   Bit#(1) wEnb_indx;
   Bit#(1) wEnb_indc;
} Ram9bWriteRequest deriving (Bits, Eq);

typedef struct {
   Bit#(9) mPatt;
} Ram9bReadRequest deriving (Bits, Eq);

typedef struct {
   Bit#(256) mIndc;
} Ram9bReadResponse deriving (Bits, Eq);

interface Ram9bx256;
   interface Put#(Ram9bWriteRequest) writeReq;
   interface Put#(Ram9bReadRequest) readReq;
   interface Get#(Ram9bReadResponse) readResp;
endinterface
module mkRam9bx256(Ram9bx256);
   let verbose = False;
   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule every1 if (verbose);
      cycle <= cycle + 1;
   endrule

   FIFO#(Bit#(16)) iVld_fifo <- mkFIFO;
   FIFO#(Bit#(256)) mIndc_fifo <- mkFIFO;

   // WWID = 1, RWID = 32, WDEP = 16384, OREG = 1, INIT = 1
`define VLDRAM AsymmetricBRAM#(Bit#(9), Bit#(16), Bit#(13), Bit#(1))
   `VLDRAM vldram <- mkAsymmetricBRAM(True, False, "VLDram");

   // WWID = 5, RWID = 40, WDEP = 4096, OREG = 0, INIT = 1
`define INDXRAM AsymmetricBRAM#(Bit#(9), Bit#(16), Bit#(11), Bit#(4))
   Vector#(4, `INDXRAM) indxram <- replicateM(mkAsymmetricBRAM(True, False, "indxRam"));

   // DWID = 32, DDEP = 32, MRDW = "DONT_CARE", RREG=ALL, INIT=1
   BRAM_Configure bramCfg = defaultValue;
   bramCfg.memorySize = 16;
   bramCfg.latency=2;
   Vector#(16, BRAM2Port#(Bit#(4), Bit#(16))) dpmlab <- replicateM(mkBRAM2Server(bramCfg));

   rule vldram_output;
      let v <- vldram.readServer.response.get;
      if (verbose) $display("vldram %d: read iVld_fifo.enq=%x", cycle, v);
      iVld_fifo.enq(v);
   endrule

   for (Integer i=0; i<4; i=i+1) begin
      rule indxram_output;
         let v <- indxram[i].readServer.response.get;
         if (verbose) $display("indxram: read response=%x", v);
         for (Integer j=0; j<4; j=j+1) begin
            Bit#(4) addr = v[(j+1)*4-1 : j*4];
            dpmlab[i*4+j].portB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: addr, datain: ?});
            if (verbose) $display("dpmlab %d: read i=%d, j=%d index=%d addr=%x", cycle, i, j, i*4+j, addr);
         end
      endrule
   end

   rule dpmlab_read_response;
      let ivld <- toGet(iVld_fifo).get;
      Bit#(256) mIndc = 0;
      for (Integer i=0; i<4; i=i+1) begin
         for (Integer j=0; j<4; j=j+1) begin
            let v <- dpmlab[i*4+j].portB.response.get;
            Vector#(16, Bit#(1)) ivld_vec = replicate(ivld[4*i+j]);
            Bit#(16) mIndcV = v & pack(ivld_vec);
            mIndc[(i*4+j+1)*16-1 : (i*4+j)*16] = mIndcV;
            if (verbose) $display("dpmlab %d: read i=%d, j=%d index=%d v=%x", cycle, i, j, i*4+j, v);
         end
      end
      mIndc_fifo.enq(mIndc);
      if (verbose) $display("dpmlab %d: mIndc=%x", cycle, pack(mIndc));
   endrule

   interface Put writeReq;
      method Action put(Ram9bWriteRequest req);
         let wIVld  = req.wIVld;
         let wEnb_iVld = req.wEnb_iVld;
         let wEnb_indx = req.wEnb_indx;
         if (wEnb_iVld == 1) begin
            Bit#(13) wAddr = {req.wPatt, req.wAddr_indx};
            vldram.writeServer.put(tuple2(wAddr, pack(wIVld)));
            if (verbose) $display("vldram %d: write to vldram wAddr=%x, data=%x", cycle, wAddr, pack(wIVld));
         end

         if (wEnb_indx == 1) begin
            for (Integer i=0; i<4; i=i+1) begin
               if (req.wAddr_indx[3:2] == fromInteger(i)) begin
                  Bit#(11) wAddr = {req.wPatt, req.wAddr_indx[1:0]};
                  indxram[i].writeServer.put(tuple2(wAddr, req.wIndx));
                  if (verbose) $display("indxram %d: write i=%x wAddr=%x, wIndx=%x", cycle, i, wAddr, req.wIndx);
               end
            end
         end

         let wAddr_indc = req.wAddr_indc;
         let wIndc = req.wIndc;
         let wEnb_indc = req.wEnb_indc;
         if (wEnb_indc == 1) begin
            for (Integer i=0; i<4; i=i+1) begin
               for (Integer j=0; j<4; j=j+1) begin
                  if ((req.wAddr_indx[3:2] == fromInteger(i)) && req.wAddr_indx[1:0] == fromInteger(j)) begin
                     if (verbose) $display("dpmlab %d: write i=%d, j=%d index=%d, addr=%x, wIndc=%x", cycle, i, j, i*4+j, wAddr_indc, wIndc);
                     dpmlab[i*4+j].portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address: wAddr_indc, datain: wIndc});
                  end
               end
            end
         end
      endmethod
   endinterface
   interface Put readReq;
      method Action put(Ram9bReadRequest req);
         let mPatt = req.mPatt;
         vldram.readServer.request.put(mPatt);
         for (Integer i=0; i<4; i=i+1) begin
            indxram[i].readServer.request.put(mPatt);
            if (verbose) $display("indxram: read patt=%x", mPatt);
         end
      endmethod
   endinterface
   interface Get readResp;
      method ActionValue#(Ram9bReadResponse) get();
         let _mIndc <- toGet(mIndc_fifo).get;
         return Ram9bReadResponse{mIndc: _mIndc};
      endmethod
   endinterface
endmodule

typedef struct {
   Bit#(9) wPatt;
   Bit#(4) wIndx;
   Bit#(16) wIndc; // sqrt(256)
   Bit#(TAdd#(TLog#(cdep), 4)) wAddr_indx; // log(depth)/2
   Bit#(4) wAddr_indc; // log(depth)/2
   Bit#(1) wIVld;
   Bit#(1) wEnb_iVld;
   Bit#(1) wEnb_indx;
   Bit#(1) wEnb_indc;
} WriteRequest#(numeric type cdep) deriving (Bits, Eq);

typedef struct {
   Bit#(9) mPatt;
} ReadRequest deriving (Bits, Eq);

typedef struct {
   Bit#(TMul#(cdep, 256)) mIndc;
} ReadResponse#(numeric type cdep) deriving (Bits, Eq);

interface Ram9b#(numeric type cdep);
   interface Put#(WriteRequest#(cdep)) writeRequest;
   interface Put#(ReadRequest) readRequest;
   interface Get#(ReadResponse#(cdep)) readResponse;
endinterface
module mkRam9b(Ram9b#(cdep));

   let verbose = False;
   Reg#(Bit#(32)) cycle <- mkReg(0);
   rule every1 if (verbose);
      cycle <= cycle + 1;
   endrule

   Vector#(cdep, Ram9bx256) ram <- replicateM(mkRam9bx256());

   interface Put writeRequest;
      method Action put(WriteRequest#(cdep) req);
         Vector#(cdep, Bool) wEnb = replicate(False);
         Vector#(cdep, Ram9bWriteRequest) requests;
         for (Integer i=0; i < valueOf(cdep); i=i+1) begin
            wEnb[i] = ((req.wAddr_indx >> 4) == fromInteger(i));
            requests[i] = Ram9bWriteRequest { wPatt: req.wPatt,
               wIndx: req.wIndx,
               wIndc: req.wIndc,
               wAddr_indx: req.wAddr_indx[3:0],
               wAddr_indc: req.wAddr_indc,
               wIVld: req.wIVld,
               wEnb_iVld: pack(unpack(req.wEnb_iVld) && wEnb[i]),
               wEnb_indx: pack(unpack(req.wEnb_indx) && wEnb[i]),
               wEnb_indc: pack(unpack(req.wEnb_indc) && wEnb[i])
            };
            ram[i].writeReq.put(requests[i]);
         end
      endmethod
   endinterface
   interface Put readRequest;
      method Action put (ReadRequest req);
         Vector#(cdep, Ram9bReadRequest) requests;
         for (Integer i=0; i < valueOf(cdep); i=i+1) begin
            requests[i] = Ram9bReadRequest{mPatt: req.mPatt};
            ram[i].readReq.put(requests[i]);
         end
         if (verbose) $display("ram9b %d: mPatt=%x", cycle, req.mPatt);
      endmethod
   endinterface
   interface Get readResponse;
      method ActionValue#(ReadResponse#(cdep)) get();
         Vector#(cdep, Bit#(256)) _mIndc;
         for (Integer i=0; i < valueOf(cdep); i=i+1) begin
            let v <- toGet(ram[i].readResp).get;
            _mIndc[i] = v.mIndc;
         end
         return ReadResponse{mIndc: pack(_mIndc)};
      endmethod
   endinterface
endmodule


fix various compilation errors

fix various compilation errors

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

// This module implements a fixed point complex multiplication
// that is intended to map smoothly onto the DSP slices in Xilinx
// FPGAs.  To this end, the signal path is 18 bits (2 bits of integer
// and 16 bits of fraction), the coefficient path is 25 bits (2 bits
// of integer and 23 bits of fraction), and the product is 43 bits
// 4 bits of integer and 39 bits of fraction).  The multiplier
// in a DSP slice is actually 18 x 25 -> 45 bits.  The additional two
// product bits are for overflow, since the complex multipler adds
// four intermediate results.

// Signal inputs and outputs are Pipe datatypes, to provide flow control.
// The module is intended for use in environments where there may be
// one result per cycle, but at slow signal rates, clock cycles may
// be skipped.  Because the logic is pipelined, there are valid
// bits that follow the signal path.  The signal is assumed to be provided
// intermittently, while the coefficients are provided on demand up to
// one per cycle.

// Because one intended application is a Channel Select filter with
// downconversion, the coefficient path supplies a "filter phase" boolean
// which indicates the start of a new sample period at the output
// intermediate frequency.

import FIFOF::*;
import SpecialFIFOs::*;
import Complex::*;
import FixedPoint::*;
import Pipe::*;
import FIFOF::*;
import SpecialFIFOs::*;
import SDRTypes::*;

typedef struct {
		Complex#(Coeff) a;
		Bit#(1) filterPhase;
		} CoeffData deriving(Bits);

typedef struct {
		Complex#(Product) y;
		Bit#(1) filterPhase;
		} ProductData deriving(Bits);

typedef struct {
		Product arxr;
		Product arxi;
		Product aixr;
		Product aixi;
		Bit#(1) filterPhase;
		} MulData deriving(Bits);

interface FPCMult;
   interface PipeIn#(Complex#(Signal)) x;
   interface PipeIn#(CoeffData) a;
   interface PipeOut#(ProductData) y;
endinterface

module mkFPCMult(FPCMult)
  provisos(Bits#(CoeffData, a__),
     Bits#(ProductData, b__),
     Bits#(MulData, c__));
   /* input registers */
   FIFOF#(CoeffData) ain <- mkPipelineFIFOF();
   FIFOF#(Complex#(Signal)) xin <- mkPipelineFIFOF();
   /* pipeline registers at output of multipliers */
   Reg#(MulData) ax <- mkReg(?);
   /* result registers */
   FIFOF#(ProductData) yout <- mkPipelineFIFOF();

   rule work;
      /* compute multiplies */

      Product arxr = fxptMult(ain.first().a.rel, xin.first.rel);
      Product aixi = fxptMult(ain.first().a.img, xin.first.img);
      Product arxi = fxptMult(ain.first().a.rel, xin.first.img);
      Product aixr = fxptMult(ain.first().a.img, xin.first.rel);
      ain.deq();
      xin.deq();
      ax <= MulData{arxr: arxr, aixi: aixi, arxi: arxi, aixr: aixr,
	 filterPhase: ain.first().filterPhase};
      /* pipeline and combine into outputs */
      yout.enq(ProductData{y: Complex{rel: ax.arxr - ax.aixi, img: ax.arxi + ax.aixr}, filterPhase: ax.filterPhase});
   endrule

   interface PipeOut y = toPipeOut(yout);
   interface PipeIn x = toPipeIn(xin);
   interface PipeIn a = toPipeIn(ain);

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.

// This module implements a fixed point complex multiplication
// that is intended to map smoothly onto the DSP slices in Xilinx
// FPGAs.  To this end, the signal path is 18 bits (2 bits of integer
// and 16 bits of fraction), the coefficient path is 25 bits (2 bits
// of integer and 23 bits of fraction), and the product is 43 bits
// 4 bits of integer and 39 bits of fraction).  The multiplier
// in a DSP slice is actually 18 x 25 -> 45 bits.  The additional two
// product bits are for overflow, since the complex multipler adds
// four intermediate results.

// Signal inputs and outputs are Pipe datatypes, to provide flow control.
// The module is intended for use in environments where there may be
// one result per cycle, but at slow signal rates, clock cycles may
// be skipped.  Because the logic is pipelined, there are valid
// bits that follow the signal path.  The signal is assumed to be provided
// intermittently, while the coefficients are provided on demand up to
// one per cycle.

// Because one intended application is a Channel Select filter with
// downconversion, the coefficient path supplies a "filter phase" boolean
// which indicates the start of a new sample period at the output
// intermediate frequency.

import SpecialFIFOs::*;
import Complex::*;
import FixedPoint::*;
import Pipe::*;
import FIFOF::*;
import SpecialFIFOs::*;
import SDRTypes::*;

typedef struct {
		Complex#(Coeff) a;
		Bit#(1) filterPhase;
		} CoeffData deriving(Bits);

typedef struct {
		Complex#(Product) y;
		Bit#(1) filterPhase;
		} ProductData deriving(Bits);

typedef struct {
		Product arxr;
		Product arxi;
		Product aixr;
		Product aixi;
		Bit#(1) filterPhase;
		} MulData deriving(Bits);

interface FPCMult;
   interface PipeIn#(Complex#(Signal)) x;
   interface PipeIn#(CoeffData) a;
   interface PipeOut#(ProductData) y;
endinterface

module mkFPCMult(FPCMult)
  provisos(Bits#(CoeffData, a__),
     Bits#(ProductData, b__),
     Bits#(MulData, c__));
   /* input registers */
   FIFOF#(CoeffData) ain <- mkPipelineFIFOF();
   FIFOF#(Complex#(Signal)) xin <- mkPipelineFIFOF();
   /* pipeline registers at output of multipliers */
   Reg#(MulData) ax <- mkReg(?);
   /* result registers */
   FIFOF#(ProductData) yout <- mkPipelineFIFOF();

   rule work;
      /* compute multiplies */
      Product arxr = fxptMult(ain.first().a.rel, xin.first.rel);
      Product aixi = fxptMult(ain.first().a.img, xin.first.img);
      Product arxi = fxptMult(ain.first().a.rel, xin.first.img);
      Product aixr = fxptMult(ain.first().a.img, xin.first.rel);
      ain.deq();
      xin.deq();
      ax <= MulData{arxr: arxr, aixi: aixi, arxi: arxi, aixr: aixr,
	 filterPhase: ain.first().filterPhase};
      /* pipeline and combine into outputs */
      yout.enq(ProductData{y: Complex{rel: ax.arxr - ax.aixi, img: ax.arxi + ax.aixr}, filterPhase: ax.filterPhase});
   endrule

   interface PipeOut y = toPipeOut(yout);
   interface PipeIn x = toPipeIn(xin);
   interface PipeIn a = toPipeIn(ain);

endmodule


prioQ: fix issue with concurrent DEQ and ENQ

introduce one cycle delay at insert_req to avoid concurrent
deq and enq access to shared register state. This is a less
optimal way to solving the problem, a better way would be
using CReg (concurrent register) to forward write data to
read port in the same cycle.

Current latency is 3 cycles, can be reduced to 2 if use CReg.

import List::*;
import Vector::*;
import BuildVector::*;
import FIFO::*;
import SpecialFIFOs::*;
import GetPut::*;
import DefaultValue::*;

import PriorityEncoder::*;

typedef 32 SIZE;

typedef struct {
    valueType v;
    priorityType p;
} Node#(type valueType, type priorityType) deriving(Bits, Eq);

instance DefaultValue#(Node#(Bit#(size_t), Bit#(size_t)));
    defaultValue = Node {
        v : 0,
        p : maxBound
    };
endinstance

interface MinPriorityQueue#(type valueType, type priorityType);
    interface Put#(Node#(valueType, priorityType)) insert_req;
    interface Get#(void) insert_res;
    method ActionValue#(Node#(valueType, priorityType)) first();
    method Action deq();
    method Action clear();
    method Action displayQueue();
endinterface

function Bit#(1) compare (Node#(Bit#(size_t), Bit#(size_t)) x,
                          Node#(Bit#(size_t), Bit#(size_t)) y);
    if (x.p > y.p)
        return 1;
    else
        return 0;
endfunction

module mkMinPriorityQueue(MinPriorityQueue#(Bit#(size_t), Bit#(size_t)));
    PE#(SIZE) priority_encoder <- mkPEncoder;
    Vector#(SIZE, Reg#(Node#(Bit#(size_t), Bit#(size_t))))
                   sorted_list <- replicateM(mkReg(defaultValue));
    Reg#(Node#(Bit#(size_t), Bit#(size_t))) node_to_insert <- mkReg(defaultValue);
    Reg#(Bit#(TLog#(SIZE))) curr_size <- mkReg(0);
    Reg#(Bit#(1)) insert_in_progress <- mkReg(0);
    FIFO#(void) insert_res_fifo <- mkBypassFIFO;
    FIFO#(Node#(Bit#(size_t), Bit#(size_t))) insert_req_fifo <- mkSizedFIFO(4);

    rule insert (insert_in_progress == 1);
        let x <- toGet(priority_encoder.bin).get;
        $display("get from pe %h", x);
        case (x) matches
           tagged Valid .index : begin
              let v = readVReg(sorted_list);
              let shiftedV = shiftOutFromN(defaultValue, v, 1);
              /*TODO: implement with map(function, vec) */
              Vector#(SIZE, Node#(Bit#(size_t), Bit#(size_t))) outV = newVector;
              for (Integer i=0; i<valueOf(SIZE); i=i+1) begin
                  if (fromInteger(i) < index)
                     outV[i] = v[i];
                  else if (fromInteger(i) == index)
                     outV[i] = node_to_insert;
                  else
                     outV[i] = shiftedV[i];
              end
              writeVReg(sorted_list, outV);
              insert_in_progress <= 0;
              curr_size <= curr_size + 1;
              insert_res_fifo.enq(?);
           end
           tagged Invalid: $display("invalid output %h", x);
        endcase
    endrule

    rule handle_insert_req (insert_in_progress == 0);
       let v <- toGet(insert_req_fifo).get;
       node_to_insert <= v;
       insert_in_progress <= 1;
       let r = map(uncurry(compare), zip(readVReg(sorted_list), replicate(v)));
       priority_encoder.oht.put(pack(r));
    endrule

    method ActionValue#(Node#(Bit#(size_t), Bit#(size_t))) first() if (curr_size > 0);
        return head(readVReg(sorted_list));
    endmethod

    method Action deq() if (insert_in_progress == 0 && curr_size > 0);
        let v = append(tail(readVReg(sorted_list)), vec(defaultValue));
        writeVReg(sorted_list, v);
        curr_size <= curr_size - 1;
    endmethod

    method Action clear() if (insert_in_progress == 0 && curr_size > 0);
        writeVReg(sorted_list, defaultValue);
        curr_size <= 0;
    endmethod

    method Action displayQueue();
        for (Integer i = 0; i < valueof(SIZE); i = i + 1)
            $display("(%d %d)", sorted_list[i].v, sorted_list[i].p);
    endmethod

    interface Put insert_req = toPut(insert_req_fifo);
    interface Get insert_res = toGet(insert_res_fifo);
endmodule

import List::*;
import Vector::*;
import BuildVector::*;
import FIFO::*;
import SpecialFIFOs::*;
import GetPut::*;
import DefaultValue::*;

import PriorityEncoder::*;

typedef 32 SIZE;

typedef struct {
    valueType v;
    priorityType p;
} Node#(type valueType, type priorityType) deriving(Bits, Eq);

instance DefaultValue#(Node#(Bit#(size_t), Bit#(size_t)));
    defaultValue = Node {
        v : 0,
        p : maxBound
    };
endinstance

interface MinPriorityQueue#(type valueType, type priorityType);
    interface Put#(Node#(valueType, priorityType)) insert_req;
    interface Get#(void) insert_res;
    method ActionValue#(Node#(valueType, priorityType)) first();
    method Action deq();
    method Action clear();
    method Action displayQueue();
endinterface

function Bit#(1) compare (Node#(Bit#(size_t), Bit#(size_t)) x,
                          Node#(Bit#(size_t), Bit#(size_t)) y);
    if (x.p > y.p)
        return 1;
    else
        return 0;
endfunction

module mkMinPriorityQueue(MinPriorityQueue#(Bit#(size_t), Bit#(size_t)));
    PE#(SIZE) priority_encoder <- mkPEncoder;
    Vector#(SIZE, Reg#(Node#(Bit#(size_t), Bit#(size_t))))
                   sorted_list <- replicateM(mkReg(defaultValue));
    Reg#(Node#(Bit#(size_t), Bit#(size_t))) node_to_insert <- mkReg(defaultValue);
    Reg#(Bit#(TLog#(SIZE))) curr_size <- mkReg(0);
    Reg#(Bit#(1)) insert_in_progress <- mkReg(0);
    FIFO#(void) insert_res_fifo <- mkBypassFIFO;

    rule insert (insert_in_progress == 1);
        let x <- toGet(priority_encoder.bin).get;
        $display("get from pe %h", x);
        case (x) matches
           tagged Valid .index : begin
              let v = readVReg(sorted_list);
              let shiftedV = shiftOutFromN(defaultValue, v, 1);
              /*TODO: implement with map(function, vec) */
              Vector#(SIZE, Node#(Bit#(size_t), Bit#(size_t))) outV = newVector;
              for (Integer i=0; i<valueOf(SIZE); i=i+1) begin
                  if (fromInteger(i) < index)
                     outV[i] = v[i];
                  else if (fromInteger(i) == index)
                     outV[i] = node_to_insert;
                  else
                     outV[i] = shiftedV[i];
              end
              writeVReg(sorted_list, outV);
              insert_in_progress <= 0;
              curr_size <= curr_size + 1;
              insert_res_fifo.enq(?);
           end
           tagged Invalid: $display("invalid output %h", x);
        endcase
    endrule

    method ActionValue#(Node#(Bit#(size_t), Bit#(size_t))) first() if (curr_size > 0);
        return head(readVReg(sorted_list));
    endmethod

    method Action deq() if (insert_in_progress == 0 && curr_size > 0);
        let v = append(tail(readVReg(sorted_list)), vec(defaultValue));
        writeVReg(sorted_list, v);
        curr_size <= curr_size - 1;
    endmethod

    method Action clear() if (insert_in_progress == 0 && curr_size > 0);
        writeVReg(sorted_list, defaultValue);
        curr_size <= 0;
    endmethod

    method Action displayQueue();
        for (Integer i = 0; i < valueof(SIZE); i = i + 1)
            $display("(%d %d)", sorted_list[i].v, sorted_list[i].p);
    endmethod

    interface Put insert_req;
        method Action put (Node#(Bit#(size_t), Bit#(size_t)) v) if (insert_in_progress == 0);
            node_to_insert <= v;
            insert_in_progress <= 1;
            let r = map(uncurry(compare), zip(readVReg(sorted_list), replicate(v)));
            priority_encoder.oht.put(pack(r));
        endmethod
    endinterface
    interface Get insert_res = toGet(insert_res_fifo);
endmodule


fix compile

fix compile

import Vector::*;
import Assert::*;
import Ehr::*;
import Fifo::*;
import Types::*;
import ProcTypes::*;
import TlbTypes::*;

// vpn -> ppn of the page containing the intermediate page table
// entry at the lowest walk level

typedef struct {
    PageWalkLevel startLevel;
    Ppn ppn; // only valid when startLevel < maxPageWalkLevel
} TranslationCacheResp deriving(Bits, Eq, FShow);

interface TranslationCache;
    method Action req(Vpn vpn);
    method TranslationCacheResp resp;
    method Action deqResp;
    method Action addEntry(Vpn vpn, PageWalkLevel level, Ppn ppn);
    method Action flush;
    method Bool flush_done;
endinterface

// ordering:
// resp < {req, addEntry}
// req C addEntry
// flush C {req, addEntry} (flush is likely to have higher urgency)

// split translation cache

// translation cache for a specific level L. This stores the PTEs at level L.
interface SingleSplitTransCache;
    method ActionValue#(Maybe#(Ppn)) req(Vpn vpn);
    method Action addEntry(Vpn vpn, Ppn ppn);
    method Action flush;
endinterface

typedef 24 SplitTransCacheSize; // size from ISCA 2010 paper
typedef Bit#(TLog#(SplitTransCacheSize)) SplitTransCacheIdx;

module mkSingleSplitTransCache#(PageWalkLevel level)(SingleSplitTransCache);
    staticAssert(level > 0 && level <= maxPageWalkLevel, "illegal level");

    Vector#(SplitTransCacheSize, Reg#(Bool)) validVec <- replicateM(mkReg(False));
    Vector#(SplitTransCacheSize, Reg#(Vpn)) vpnVec <- replicateM(mkRegU);
    Vector#(SplitTransCacheSize, Reg#(Ppn)) ppnVec <- replicateM(mkRegU);

    // bit-LRU replacement. To reduce cycle time, we update LRU bits in the
    // next cycle after we touch an entry. However, when we have two
    // consecutive cycles inserting new entries, the latter insertion should
    // see the updates to LRU bits made by the former insertion; otherwise the
    // latter will insert to the same slot as the former one.
    Ehr#(2, Bit#(SplitTransCacheSize)) lruBit <- mkEhr(0);
    Reg#(Bit#(SplitTransCacheSize)) lruBit_upd = lruBit[0]; // write
    Reg#(Bit#(SplitTransCacheSize)) lruBit_add = lruBit[1]; // read
    // reg as 1 cycle delay for update LRU
    Ehr#(2, Maybe#(SplitTransCacheIdx)) updRepIdx <- mkEhr(Invalid);
    Reg#(Maybe#(SplitTransCacheIdx)) updRepIdx_deq = updRepIdx[0];
    Reg#(Maybe#(SplitTransCacheIdx)) updRepIdx_enq = updRepIdx[1];
    // randomly choose an LRU idx at replacement time
    Reg#(SplitTransCacheIdx) randIdx <- mkReg(0);

    // don't do anything at flush time
    PulseWire flushEn <- mkPulseWire;

    rule incRandIdx;
        randIdx <= randIdx + 1;
    endrule

    rule doUpdateRep(updRepIdx_deq matches tagged Valid .idx &&& !flushEn);
        updRepIdx_deq <= Invalid;
        // update LRU bits
        Bit#(SplitTransCacheSize) val = lruBit_upd;
        val[idx] = 1;
        if(val == maxBound) begin
            val = 0;
            val[idx] = 1;
        end
        lruBit_upd <= val;
    endrule

    method ActionValue#(Maybe#(Ppn)) req(Vpn vpn) if(updRepIdx_enq == Invalid && !flushEn);
        function Bool hit(SplitTransCacheIdx i);
            let vpn_match = getMaskedVpn(vpn, level) == getMaskedVpn(vpnVec[i], level);
            return validVec[i] && vpn_match;
        endfunction
        Vector#(SplitTransCacheSize, SplitTransCacheIdx) idxVec = genWith(fromInteger);
        if(find(hit, idxVec) matches tagged Valid .i) begin
            updRepIdx_enq <= Valid (i); // update LRU
            return Valid (ppnVec[i]);
        end
        else begin
            return Invalid;
        end
    endmethod

    method Action addEntry(Vpn vpn, Ppn ppn) if(updRepIdx_enq == Invalid && !flushEn);
        SplitTransCacheIdx addIdx;
        if(findIndex( \== (False) , readVReg(validVec) ) matches tagged Valid .idx) begin
            // get empty slot
            addIdx = pack(idx);
        end
        else begin
            // find LRU slot (lruBit[i] = 0 means i is LRU slot)
            Vector#(SplitTransCacheSize, Bool) isLRU = unpack(~lruBit_add);
            if(isLRU[randIdx]) begin
                addIdx = randIdx;
            end
            else if(findIndex(id, isLRU) matches tagged Valid .idx) begin
                addIdx = pack(idx);
            end
            else begin
                addIdx = 0; // this is actually impossible
                doAssert(False, "must have at least 1 LRU slot");
            end
        end
        // update slot
        validVec[addIdx] <= True;
        vpnVec[addIdx] <= getMaskedVpn(vpn, level);
        ppnVec[addIdx] <= ppn; // don't mask ppn, intermidate PTE point to a 4KB page
        // update LRU bits
        updRepIdx_enq <= Valid (addIdx);
    endmethod

    method Action flush;
        writeVReg(validVec, replicate(False));
        // also reset LRU bits
        lruBit_upd <= 0;
        updRepIdx_deq <= Invalid;
        // signal fire
        flushEn.send;
    endmethod
endmodule

(* synthesize *)
module mkSplitTransCache(TranslationCache);
    Vector#(TSub#(NumPageWalkLevels, 1), SingleSplitTransCache) caches;
    for(PageWalkLevel i = 0; i < maxPageWalkLevel; i = i+1) begin
        caches[i] <- mkSingleSplitTransCache(i + 1);
    end

    Fifo#(1, TranslationCacheResp) respQ <- mkPipelineFifo;

    method Action req(Vpn vpn);
        TranslationCacheResp resp;
        Vector#(TSub#(NumPageWalkLevels, 1), Maybe#(Ppn)) hits;
        for(PageWalkLevel i = 0; i < maxPageWalkLevel; i = i+1) begin
            hits[i] <- caches[i].req(vpn); // cached page walk level i+1
        end
        // XXX hit in lower level has priority
        if(findIndex(isValid, hits) matches tagged Valid .idx) begin
            resp = TranslationCacheResp {
                startLevel: zeroExtend(pack(idx)),
                ppn: validValue(hits[idx])
            };
        end
        else begin
            resp = TranslationCacheResp {
                startLevel: maxPageWalkLevel,
                ppn: ?
            };
        end
        respQ.enq(resp);
    endmethod

    method TranslationCacheResp resp = respQ.first;

    method Action deqResp;
        respQ.deq;
    endmethod

    // the guard makes resp < addEntry, so pending req is ordered before the
    // newly add entry (so in case of miss, the pending req could mark itself
    // waiting on the page walk that is just about to addEntry, and get the
    // bypass)
    method Action addEntry(Vpn vpn, PageWalkLevel level, Ppn ppn) if(respQ.notFull);
        doAssert(level > 0, "cannot be level 0");
        doAssert(level <= maxPageWalkLevel, "level too large");
        caches[level - 1].addEntry(vpn, ppn);
    endmethod

    method Action flush;
        for(PageWalkLevel i = 0; i < maxPageWalkLevel; i = i+1) begin
            caches[i].flush;
        end
    endmethod

    method Bool flush_done = True;
endmodule

(* synthesize *)
module mkNullTransCache(TranslationCache);
    Fifo#(1, void) reqQ <- mkPipelineFifo;

    method Action req(Vpn vpn);
        reqQ.enq(?);
    endmethod
    method Action deqResp;
        reqQ.deq;
    endmethod
    method TranslationCacheResp resp if(reqQ.notEmpty);
        return TranslationCacheResp {
            startLevel: maxPageWalkLevel,
            ppn: ?
        };
    endmethod
    method Action addEntry(Vpn vpn, PageWalkLevel level, Ppn ppn);
        noAction;
    endmethod
    method Action flush;
        noAction;
    endmethod
    method Bool flush_done = True;
endmodule

import Vector::*;
import Assert::*;
import Ehr::*;
import Fifo::*;
import Types::*;
import ProcTypes::*;
import TlbTypes::*;

// vpn -> ppn of the page containing the intermediate page table
// entry at the lowest walk level

typedef struct {
    PageWalkLevel startLevel;
    Ppn ppn; // only valid when startLevel < maxPageWalkLevel
} TranslationCacheResp deriving(Bits, Eq, FShow);

interface TranslationCache;
    method Action req(Vpn vpn);
    method TranslationCacheResp resp;
    method Action deqResp;
    method Action addEntry(Vpn vpn, PageWalkLevel level, Ppn ppn);
    method Action flush;
    method Bool flush_done;
endinterface

// ordering:
// resp < {req, addEntry}
// req C addEntry
// flush C {req, addEntry} (flush is likely to have higher urgency)

// split translation cache

// translation cache for a specific level L. This stores the PTEs at level L.
interface SingleSplitTransCache;
    method ActionValue#(Maybe#(Ppn)) req(Vpn vpn);
    method Action addEntry(Vpn vpn, Ppn ppn);
    method Action flush;
endinterface

typedef 24 SplitTransCacheSize; // size from ISCA 2010 paper
typedef Bit#(TLog#(SplitTransCacheSize)) SplitTransCacheIdx;

module mkSingleSplitTransCache#(PageWalkLevel level)(SingleSplitTransCache);
    staticAssert(level > 0 && level <= maxPageWalkLevel, "illegal level");

    Vector#(SplitTransCacheSize, Reg#(Bool)) validVec <- replicateM(mkReg(False));
    Vector#(SplitTransCacheSize, Reg#(Vpn)) vpnVec <- replicateM(mkRegU);
    Vector#(SplitTransCacheSize, Reg#(Ppn)) ppnVec <- replicateM(mkRegU);

    // bit-LRU replacement. To reduce cycle time, we update LRU bits in the
    // next cycle after we touch an entry. However, when we have two
    // consecutive cycles inserting new entries, the latter insertion should
    // see the updates to LRU bits made by the former insertion; otherwise the
    // latter will insert to the same slot as the former one.
    Ehr#(2, Bit#(SplitTransCacheSize)) lruBit <- mkEhr(0);
    Reg#(Bit#(SplitTransCacheSize)) lruBit_upd = lruBit[0]; // write
    Reg#(Bit#(SplitTransCacheSize)) lruBit_add = lruBit[1]; // read
    // reg as 1 cycle delay for update LRU
    Ehr#(2, Maybe#(SplitTransCacheIdx)) updRepIdx <- mkEhr(Invalid);
    Reg#(Maybe#(SplitTransCacheIdx)) updRepIdx_deq = updRepIdx[0];
    Reg#(Maybe#(SplitTransCacheIdx)) updRepIdx_enq = updRepIdx[1];
    // randomly choose an LRU idx at replacement time
    Reg#(SplitTransCacheIdx) randIdx <- mkReg(0);

    // don't do anything at flush time
    PulseWire flushEn <- mkPulseWire;

    rule incRandIdx;
        randIdx <= randIdx + 1;
    endrule

    rule doUpdateRep(updRepIdx_deq matches tagged Valid .idx &&& !flushEn);
        updRepIdx_deq <= Invalid;
        // update LRU bits
        Bit#(SplitTransCacheSize) val = lruBit_upd;
        val[idx] = 1;
        if(val == maxBound) begin
            val = 0;
            val[idx] = 1;
        end
        lruBit_upd <= val;
    endrule

    method ActionValue#(Maybe#(Ppn)) req(Vpn vpn) if(updRepIdx_enq == Invalid && !flushEn);
        function Bool hit(SplitTransCacheIdx i);
            let vpn_match = getMaskedVpn(vpn, level) == getMaskedVpn(vpnVec[i], level);
            return validVec[i] && vpn_match;
        endfunction
        Vector#(SplitTransCacheSize, SplitTransCacheIdx) idxVec = genWith(fromInteger);
        if(find(hit, idxVec) matches tagged Valid .i) begin
            updRepIdx_enq <= Valid (i); // update LRU
            return Valid (ppnVec[i]);
        end
        else begin
            return Invalid;
        end
    endmethod

    method Action addEntry(Vpn vpn, Ppn ppn) if(updRepIdx_enq == Invalid && !flushEn);
        SplitTransCacheIdx addIdx;
        if(findIndex( \== (False) , readVReg(validVec) ) matches tagged Valid .idx) begin
            // get empty slot
            addIdx = pack(idx);
        end
        else begin
            // find LRU slot (lruBit[i] = 0 means i is LRU slot)
            Vector#(SplitTransCacheSize, Bool) isLRU = unpack(~lruBit_add);
            if(isLRU[randIdx]) begin
                addIdx = randIdx;
            end
            else if(findIndex(id, isLRU) matches tagged Valid .idx) begin
                addIdx = pack(idx);
            end
            else begin
                addIdx = 0; // this is actually impossible
                doAssert(False, "must have at least 1 LRU slot");
            end
        end
        // update slot
        validVec[addIdx] <= True;
        vpnVec[addIdx] <= getMaskedVpn(vpn, level);
        ppnVec[addIdx] <= ppn; // don't mask ppn, intermidate PTE point to a 4KB page
        // update LRU bits
        updRepIdx_enq <= Valid (addIdx);
    endmethod

    method Action flush;
        writeVReg(validVec, replicate(False));
        // also reset LRU bits
        lruBit_upd <= 0;
        updRepIdx_deq <= Invalid;
        // signal fire
        flushEn.send;
    endmethod
endmodule

(* synthesize *)
module mkSplitTransCache(TranslationCache);
    Vector#(TSub#(NumPageWalkLevels, 1), SingleSplitTransCache) caches;
    for(PageWalkLevel i = 0; i < maxPageWalkLevel; i = i+1) begin
        caches[i] <- mkSingleSplitTransCache(i + 1);
    end

    Fifo#(1, TranslationCacheResp) respQ <- mkPipelineFifo;

    method Action req(Vpn vpn);
        TranslationCacheResp resp;
        Vector#(TSub#(NumPageWalkLevels, 1), Maybe#(Ppn)) hits;
        for(PageWalkLevel i = 0; i < maxPageWalkLevel; i = i+1) begin
            hits[i] <- caches[i].req(vpn); // cached page walk level i+1
        end
        // XXX hit in lower level has priority
        if(findIndex(isValid, hits) matches tagged Valid .idx) begin
            resp = TranslationCacheResp {
                startLevel: zeroExtend(pack(idx)),
                ppn: validValue(hits[idx])
            };
        end
        else begin
            resp = TranslationCacheResp {
                startLevel: maxPageWalkLevel,
                ppn: ?
            };
        end
        respQ.enq(resp);
    endmethod

    method TranslationCacheResp resp = respQ.first;

    method Action deqResp;
        respQ.deq;
    endmethod

    // the guard makes resp < addEntry, so pending req is ordered before the
    // newly add entry (so in case of miss, the pending req could mark itself
    // waiting on the page walk that is just about to addEntry, and get the
    // bypass)
    method Action addEntry(Vpn vpn, PageWalkLevel level, Ppn ppn) if(respQ.notFull);
        doAssert(level > 0, "cannot be level 0");
        doAssert(level <= maxPageWalkLevel, "level too large");
        caches[level - 1].addEntry(vpn, ppn);
    endmethod

    method Action flush;
        for(PageWalkLevel i = 0; i < maxPageWalkLevel; i = i+1) begin
            caches[i].flush;
        end
    endmethod

    method Bool flush_done = True;
endmodule

(* synthesize *)
module mkNullTransCache(TranslationCache);
    Fifo#(1, void) reqQ <- mkPipelineFifo;

    method Action req(Vpn vpn);
        reqQ.enq(?);
    endmethod
    method Action deqResp;
        reqQ.deq;
    endmethod
    method TranslationCacheResp resp if(req.notEmpty);
        return TranslationCacheResp {
            startLevel: maxPageWalkLevel,
            ppn: ?
        };
    endmethod
    method Action addEntry(Vpn vpn, PageWalkLevel level, Ppn ppn);
        noAction;
    endmethod
    method Action flush;
        noAction;
    endmethod
    method Bool flush_done = True;
endmodule


added fifo18 to serdes line code.

added fifo18 to serdes line code.

Related git tag:
   imageon 58c3cfee30b49f1019eaa09e152a6e8a1a87ffe7

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

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

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

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

import Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
   method Action                 ibufds_out(Bit#(1) v);
   method Action                 align_start(Bit#(1) v);
   method Bit#(1)                align_busy();
   method Bit#(1)                aligned();
   method Bit#(3)                samplein();
   method Action                 autoalign(Bit#(1) v);
   method Action                 training(Bit#(10) v);
   method Action                 manual_tap(Bit#(10) v);
   method Action                 delay_wren(Bit#(1) v);
   method Action                 fifo_wren(Bit#(1) v);
   method Action                 reset(Bit#(1) v);
   method Bit#(1)                fifo_wren_sync();
   //method Bit#(1)                fifo_reset();
   method Reset                  fifo_reset();
   method Bit#(10)               dataout();
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Clock serdest)(Iserdesbvi);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   input_clock clk (CLK) = serdest;
   input_clock clkdiv (CLKDIV) = clkdiv;
   default_clock clock(CLOCK);
       method              ibufds_out(IBUFDS_OUT) enable((*inhigh*) en0); // clocked_by () reset_by ()
      method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
      method ALIGN_BUSY       align_busy() clocked_by (clock);
      method ALIGNED          aligned() clocked_by (clock);
      method SAMPLEIN samplein() clocked_by (clock);
      //method SAMPLEINLASTBIT  sampleinlastbit() clocked_by (clock);
      //method SAMPLEINOTHERBIT sampleinotherbit() clocked_by (clock);
      method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
      method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
      method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
      method                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv);
      method FIFO_WREN_SYNC   fifo_wren_sync() clocked_by (clock);
   output_reset fifo_reset(FIFO_RESET);
      method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv);
      method                  reset(RESET) enable((*inhigh*) en16) clocked_by (clkdiv);
      method FIFO_DATAOUT  dataout() clocked_by(clock);
   schedule (fifo_wren, reset, delay_wren) CF (fifo_wren, reset, delay_wren);
   schedule (ibufds_out, align_start, autoalign, training, manual_tap, dataout)
      CF (ibufds_out, align_start, autoalign, training, manual_tap, dataout);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
   method Action                 ibufds_out(Bit#(1) v);
   //method Action                 align_start(Bit#(1) v);
   method Bit#(1)                align_busy();
   method Bit#(1)                aligned();
   method Bit#(1)                sampleinfirstbit();
   method Bit#(1)                sampleinlastbit();
   method Bit#(1)                sampleinotherbit();
   //method Action                 autoalign(Bit#(1) v);
   //method Action                 training(Bit#(10) v);
   //method Action                 manual_tap(Bit#(10) v);
   //method Action                 rden(Bit#(1) v);
   method Action                 delay_wren(Bit#(1) v);
   method Action                 fifo_wren(Bit#(1) v);
   method Action                 reset(Bit#(1) v);
   method Bit#(1)                empty();
   method Bit#(10)               dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action   di(Bit#(16) v);
   method Action   dip(Bit#(2) v);
   method Action   rden(Bit#(1) v);
   method Action   wren(Bit#(1) v);
   method Bit#(16) dataout();
   method Bit#(1)  empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    // reset RST;

    method          di(DI) enable((*inhigh*) en0); // clocked_by () reset_by ()
    method          dip(DIP) enable((*inhigh*) en1); // clocked_by () reset_by ()
    method          rden(RDEN) enable((*inhigh*) en2); // clocked_by () reset_by ()
    method          wren(WREN) enable((*inhigh*) en3); // clocked_by () reset_by ()
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
   schedule (di, dip, rden, wren) CF (di, dip, rden, wren);
endmodule: mkFIFO18
module mkIserdesDatadeser#(Clock clkdiv, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);
    Iserdesbvi serdes_v <- mkIserdesbvi(clkdiv, serdest);
    Wire#(Bit#(3)) samplein_wire <- mkDWire(0);
    FIFO18 dfifo <- mkFIFO18(clkdiv, reset_by serdes_v.fifo_reset);

    rule ssrule;
        dfifo.di({6'b0,serdes_v.dataout()});
        dfifo.wren(serdes_v.fifo_wren_sync());
    endrule

    rule serdesrule;
    serdes_v.align_start(align_start);
    serdes_v.autoalign(autoalign);
    serdes_v.training(training);
    serdes_v.manual_tap(manual_tap);
    dfifo.rden(rden);
    dfifo.dip(2'b00);
    endrule

    rule samplein_rule;
    samplein_wire <= serdes_v.samplein();
    endrule

    method Action ibufds_out(Bit#(1) v);
        serdes_v.ibufds_out(v);
    endmethod
    method Bit#(1)                align_busy();
        return serdes_v.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serdes_v.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return samplein_wire[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return samplein_wire[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return samplein_wire[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        serdes_v.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        serdes_v.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) v);
        serdes_v.reset(v);
    endmethod
    method Bit#(1)                empty();
        //return serdes_v.empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        //return serdes_v.dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufds_out(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    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 Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface IserdesDatadeser;
   method Action                 ibufds_out(Bit#(1) v);
   method Action                 align_start(Bit#(1) v);
   method Bit#(1)                align_busy();
   method Bit#(1)                aligned();
   method Bit#(1)                sampleinfirstbit();
   method Bit#(1)                sampleinlastbit();
   method Bit#(1)                sampleinotherbit();
   method Action                 autoalign(Bit#(1) v);
   method Action                 training(Bit#(10) v);
   method Action                 manual_tap(Bit#(10) v);
   method Action                 rden(Bit#(1) v);
   method Action                 delay_wren(Bit#(1) v);
   method Action                 fifo_wren(Bit#(1) v);
   method Action                 reset(Bit#(1) v);
   method Bit#(1)                empty();
   method Bit#(10)               dataout();
endinterface: IserdesDatadeser

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Clock serdest)(IserdesDatadeser);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   input_clock clk (CLK) = serdest;
   input_clock clkdiv (CLKDIV) = clkdiv;
   default_clock clock(CLOCK);
       method              ibufds_out(IBUFDS_OUT) enable((*inhigh*) en0); // clocked_by () reset_by ()
      method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
      method ALIGN_BUSY       align_busy() clocked_by (clock);
      method ALIGNED          aligned() clocked_by (clock);
      method SAMPLEINFIRSTBIT sampleinfirstbit() clocked_by (clock);
      method SAMPLEINLASTBIT  sampleinlastbit() clocked_by (clock);
      method SAMPLEINOTHERBIT sampleinotherbit() clocked_by (clock);
      method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
      method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
      method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
      method                  rden(FIFO_RDEN) enable((*inhigh*) en12) clocked_by (clock);
      method                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv);
      method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv);
      method                  reset(RESET) enable((*inhigh*) en16) clocked_by (clkdiv);
      method FIFO_EMPTY    empty() clocked_by (clock);
      method FIFO_DATAOUT  dataout() clocked_by(clock);
   schedule (fifo_wren, reset, delay_wren) CF (fifo_wren, reset, delay_wren);
   schedule (ibufds_out, align_start, autoalign, training, manual_tap, rden, dataout)
      CF (ibufds_out, align_start, autoalign, training, manual_tap, rden, dataout);
endmodule: mkIserdesbvi

module mkIserdesDatadeser#(Clock clkdiv, Clock serdest, Bit#(1) align_start,
   Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);
    IserdesDatadeser serdes_v <- mkIserdesbvi(clkdiv, serdest);
    rule serdesrule;
    serdes_v.align_start(align_start);
    serdes_v.autoalign(autoalign);
    serdes_v.training(training);
    serdes_v.manual_tap(manual_tap);
    serdes_v.rden(rden);
    endrule
    method Action ibufds_out(Bit#(1) v);
        serdes_v.ibufds_out(v);
    endmethod
    method Bit#(1)                align_busy();
        return serdes_v.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serdes_v.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serdes_v.sampleinfirstbit();
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serdes_v.sampleinlastbit();
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serdes_v.sampleinotherbit();
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        serdes_v.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        serdes_v.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) v);
        serdes_v.reset(v);
    endmethod
    method Bit#(1)                empty();
        return serdes_v.empty();
    endmethod
    method Bit#(10)               dataout();
        return serdes_v.dataout();
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufds_out(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(~serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule


remove package

remove package

package TinyTestBench;

import FIFO::*;
import GetPut::*;
import StmtFSM::*;
import TinyTypes::*;
import TinyAsm::*;
import Tiny3::*;
import BRAM::*;

interface Tiny3Indication;
   method Action outputdata(Bit#(32) v);
   method Action inputresponse();
endinterface

interface Tiny3Request;
   method Action inputdata(Bit#(32) v);
endinterface

module mkTiny3Request(Tiny3Indication indication)(Tiny3Request);

   /********** the program we wish to assemble **********/
   function List#(AsmLineT) my_program(function ImmT findaddr(String label)) =
      cons(asmi("",    0, 0), // put 0 in r0
      cons(asmi("",    1, 10), // put 10 in r1
      cons(asmi("",    2, findaddr("loop")), // loop address in r2
      cons(asm("loop", OpOut, FDECb, ShiftNone, SkipNever, 1, 0, 1), // r1-- and output
      cons(asm("",     OpJump, FaORb, ShiftNone, SkipZero, 3, 2, 0), // jump r2 if not zero
      cons(asm("",     OpReserved, Freserved, ShiftNone, SkipNever, 0, 0, 0), // stop processor
      tagged Nil))))));

   InstructionROM_T irom = assembler(my_program);

   TinyCompIfc tiny <- mkTinyComp(irom);

   rule handle_output;
      let out <- tiny.out.get();
      indication.outputdata(out);
      $display("%05t: output = %d\n",$time,out);
   endrule

   method Action inputdata(Bit#(32) v);
      tiny.in(v);
      indication.inputresponse();
   endmethod

endmodule

endpackage: TinyTestBench


remove enum, which wasn't used, change index type to Bit#(16)

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

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

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

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

import Repeat::*;
import Vector::*;

interface PortalPerfRequest;
   method Action swallow();
   method Action swallowl(Bit#(32) v1);
   method Action swallowll(Bit#(32) v1, Bit#(32) v2);
   method Action swallowlll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3);
   method Action swallowllll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3, Bit#(32) v4);
   method Action swallowd(Bit#(64) v1);
   method Action swallowdd(Bit#(64) v1, Bit#(64) v2);
   method Action swallowddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3);
   method Action swallowdddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3, Bit#(64) v4);
   method Action startspit(Bit#(16), spitType, Bit#(16) loops);
endinterface

interface PortalPerfIndication;
   method Action spit();
   method Action spitl(Bit#(32) v1);
   method Action spitll(Bit#(32) v1, Bit#(32) v2);
   method Action spitlll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3);
   method Action spitllll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3, Bit#(32) v4);
   method Action spitd(Bit#(64) v1);
   method Action spitdd(Bit#(64) v1, Bit#(64) v2);
   method Action spitddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3);
   method Action spitdddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3, Bit#(64) v4);
endinterface

module mkPortalPerfRequest#(PortalPerfIndication indication) (PortalPerfRequest);

   function Action dospit();
      return
	 action
	 indication.spit();
	 endaction
	 ;
   endfunction

   function Action dospitl();
      return ( action
	 indication.spit();
	 indication.spitl(sinkl1);
	 endaction );
   endfunction

   function Action dospitll();
      return ( action
	 indication.spit();
	 indication.spitll(sinkll1, sinkll2);
	 endaction );
   endfunction

   function Action dospitlll();
      return ( action
	 indication.spit();
	 indication.spitlll(sinklll1, sinklll2, sinklll3);
	 endaction );
   endfunction

   function Action dospitllll();
      return ( action
	 indication.spit();
	 indication.spitllll(sinkllll1, sinkllll2, sinkllll3, sinkllll4);
	 endaction );
   endfunction

   function Action dospitd();
      return ( action
	 indication.spit();
	 indication.spitd(sinkd1);
	 endaction );
   endfunction

   function Action dospitdd();
      return ( action
	 indication.spit();
	 indication.spitdd(sinkdd1, sinkdd2);
	 endaction );
   endfunction

   function Action dospitddd();
      return ( action
	 indication.spit();
	 indication.spitddd(sinkddd1, sinkddd2, sinkddd3);
	 endaction );
   endfunction

   function Action dospitdddd();
      return ( action
	 indication.spit();
	 indication.spitdddd(sinkdddd1, sinkdddd2, sinkdddd3, sinkdddd4);
	 endaction );
   endfunction

   Reg#(Bit#(32)) sinkl1 <- mkReg(0);

   Reg#(Bit#(32)) sinkll1 <- mkReg(0);
   Reg#(Bit#(32)) sinkll2 <- mkReg(0);

   Reg#(Bit#(32)) sinklll1 <- mkReg(0);
   Reg#(Bit#(32)) sinklll2 <- mkReg(0);
   Reg#(Bit#(32)) sinklll3 <- mkReg(0);

   Reg#(Bit#(32)) sinkllll1 <- mkReg(0);
   Reg#(Bit#(32)) sinkllll2 <- mkReg(0);
   Reg#(Bit#(32)) sinkllll3 <- mkReg(0);
   Reg#(Bit#(32)) sinkllll4 <- mkReg(0);

   Reg#(Bit#(64)) sinkd1 <- mkReg(0);

   Reg#(Bit#(64)) sinkdd1 <- mkReg(0);
   Reg#(Bit#(64)) sinkdd2 <- mkReg(0);

   Reg#(Bit#(64)) sinkddd1 <- mkReg(0);
   Reg#(Bit#(64)) sinkddd2 <- mkReg(0);
   Reg#(Bit#(64)) sinkddd3 <- mkReg(0);

   Reg#(Bit#(64)) sinkdddd1 <- mkReg(0);
   Reg#(Bit#(64)) sinkdddd2 <- mkReg(0);
   Reg#(Bit#(64)) sinkdddd3 <- mkReg(0);
   Reg#(Bit#(64)) sinkdddd4 <- mkReg(0);

   Vector#(9, Repeat) rfns = ?;
   rfns[0] <- mkRepeat(dospit);
   rfns[1] <- mkRepeat(dospitl);
   rfns[2] <- mkRepeat(dospitll);
   rfns[3] <- mkRepeat(dospitlll);
   rfns[4] <- mkRepeat(dospitllll);
   rfns[5] <- mkRepeat(dospitd);
   rfns[6] <- mkRepeat(dospitdd);
   rfns[7] <- mkRepeat(dospitddd);
   rfns[8] <- mkRepeat(dospitdddd);
   Reg#(Bit#(16)) loops <- mkReg(0);

   method Action swallowl(Bit#(32) v1);
      sinkl1 <= v1;
   endmethod

   method Action swallow();
   endmethod

   method Action swallowll(Bit#(32) v1, Bit#(32) v2);
      sinkll1 <= v1;
      sinkll2 <= v2;
   endmethod

   method Action swallowlll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3);
      sinklll1 <= v1;
      sinklll2 <= v2;
      sinklll3 <= v3;
   endmethod

   method Action swallowllll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3, Bit#(32) v4);
      sinkllll1 <= v1;
      sinkllll2 <= v2;
      sinkllll3 <= v3;
      sinkllll4 <= v4;
   endmethod

   method Action swallowd(Bit#(64) v1);
      sinkd1 <= v1;
   endmethod

   method Action swallowdd(Bit#(64) v1, Bit#(64) v2);
      sinkdd1 <= v1;
      sinkdd2 <= v2;
   endmethod

   method Action swallowddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3);
      sinkddd1 <= v1;
      sinkddd2 <= v2;
      sinkddd3 <= v3;
   endmethod

   method Action swallowdddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3, Bit#(64) v4
      );
      sinkdddd1 <= v1;
      sinkdddd2 <= v2;
      sinkdddd3 <= v3;
      sinkdddd4 <= v4;
   endmethod

   method Action startspit(SpitType spitType, Bit#(16) loops);
      dofns[spittype].do(loops);
   endmethod

endmodule

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

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

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

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

import Repeat::*;
import Vector::*;

typedef enum { sp, spl, spll, splll, spllll, spd, spdd, spddd, spdddd } SpitType deriving (Bits);

interface PortalPerfRequest;
   method Action swallow();
   method Action swallowl(Bit#(32) v1);
   method Action swallowll(Bit#(32) v1, Bit#(32) v2);
   method Action swallowlll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3);
   method Action swallowllll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3, Bit#(32) v4);
   method Action swallowd(Bit#(64) v1);
   method Action swallowdd(Bit#(64) v1, Bit#(64) v2);
   method Action swallowddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3);
   method Action swallowdddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3, Bit#(64) v4);
   method Action startspit(SpitType spitType, Bit#(16) loops);
endinterface

interface PortalPerfIndication;
   method Action spit();
   method Action spitl(Bit#(32) v1);
   method Action spitll(Bit#(32) v1, Bit#(32) v2);
   method Action spitlll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3);
   method Action spitllll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3, Bit#(32) v4);
   method Action spitd(Bit#(64) v1);
   method Action spitdd(Bit#(64) v1, Bit#(64) v2);
   method Action spitddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3);
   method Action spitdddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3, Bit#(64) v4);
endinterface

module mkPortalPerfRequest#(PortalPerfIndication indication) (PortalPerfRequest);

   function Action dospit();
      return
	 action
	 indication.spit();
	 endaction
	 ;
   endfunction

   function Action dospitl();
      return ( action
	 indication.spit();
	 indication.spitl(sinkl1);
	 endaction );
   endfunction

   function Action dospitll();
      return ( action
	 indication.spit();
	 indication.spitll(sinkll1, sinkll2);
	 endaction );
   endfunction

   function Action dospitlll();
      return ( action
	 indication.spit();
	 indication.spitlll(sinklll1, sinklll2, sinklll3);
	 endaction );
   endfunction

   function Action dospitllll();
      return ( action
	 indication.spit();
	 indication.spitllll(sinkllll1, sinkllll2, sinkllll3, sinkllll4);
	 endaction );
   endfunction

   function Action dospitd();
      return ( action
	 indication.spit();
	 indication.spitd(sinkd1);
	 endaction );
   endfunction

   function Action dospitdd();
      return ( action
	 indication.spit();
	 indication.spitdd(sinkdd1, sinkdd2);
	 endaction );
   endfunction

   function Action dospitddd();
      return ( action
	 indication.spit();
	 indication.spitddd(sinkddd1, sinkddd2, sinkddd3);
	 endaction );
   endfunction

   function Action dospitdddd();
      return ( action
	 indication.spit();
	 indication.spitdddd(sinkdddd1, sinkdddd2, sinkdddd3, sinkdddd4);
	 endaction );
   endfunction

   Reg#(Bit#(32)) sinkl1 <- mkReg(0);

   Reg#(Bit#(32)) sinkll1 <- mkReg(0);
   Reg#(Bit#(32)) sinkll2 <- mkReg(0);

   Reg#(Bit#(32)) sinklll1 <- mkReg(0);
   Reg#(Bit#(32)) sinklll2 <- mkReg(0);
   Reg#(Bit#(32)) sinklll3 <- mkReg(0);

   Reg#(Bit#(32)) sinkllll1 <- mkReg(0);
   Reg#(Bit#(32)) sinkllll2 <- mkReg(0);
   Reg#(Bit#(32)) sinkllll3 <- mkReg(0);
   Reg#(Bit#(32)) sinkllll4 <- mkReg(0);

   Reg#(Bit#(64)) sinkd1 <- mkReg(0);

   Reg#(Bit#(64)) sinkdd1 <- mkReg(0);
   Reg#(Bit#(64)) sinkdd2 <- mkReg(0);

   Reg#(Bit#(64)) sinkddd1 <- mkReg(0);
   Reg#(Bit#(64)) sinkddd2 <- mkReg(0);
   Reg#(Bit#(64)) sinkddd3 <- mkReg(0);

   Reg#(Bit#(64)) sinkdddd1 <- mkReg(0);
   Reg#(Bit#(64)) sinkdddd2 <- mkReg(0);
   Reg#(Bit#(64)) sinkdddd3 <- mkReg(0);
   Reg#(Bit#(64)) sinkdddd4 <- mkReg(0);

   Vector#(9, Repeat) rfns = ?;
   rfns[0] <- mkRepeat(dospit);
   rfns[1] <- mkRepeat(dospitl);
   rfns[2] <- mkRepeat(dospitll);
   rfns[3] <- mkRepeat(dospitlll);
   rfns[4] <- mkRepeat(dospitllll);
   rfns[5] <- mkRepeat(dospitd);
   rfns[6] <- mkRepeat(dospitdd);
   rfns[7] <- mkRepeat(dospitddd);
   rfns[8] <- mkRepeat(dospitdddd);
   Reg#(Bit#(16)) loops <- mkReg(0);

   method Action swallowl(Bit#(32) v1);
      sinkl1 <= v1;
   endmethod

   method Action swallow();
   endmethod

   method Action swallowll(Bit#(32) v1, Bit#(32) v2);
      sinkll1 <= v1;
      sinkll2 <= v2;
   endmethod

   method Action swallowlll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3);
      sinklll1 <= v1;
      sinklll2 <= v2;
      sinklll3 <= v3;
   endmethod

   method Action swallowllll(Bit#(32) v1, Bit#(32) v2, Bit#(32) v3, Bit#(32) v4);
      sinkllll1 <= v1;
      sinkllll2 <= v2;
      sinkllll3 <= v3;
      sinkllll4 <= v4;
   endmethod

   method Action swallowd(Bit#(64) v1);
      sinkd1 <= v1;
   endmethod

   method Action swallowdd(Bit#(64) v1, Bit#(64) v2);
      sinkdd1 <= v1;
      sinkdd2 <= v2;
   endmethod

   method Action swallowddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3);
      sinkddd1 <= v1;
      sinkddd2 <= v2;
      sinkddd3 <= v3;
   endmethod

   method Action swallowdddd(Bit#(64) v1, Bit#(64) v2, Bit#(64) v3, Bit#(64) v4
      );
      sinkdddd1 <= v1;
      sinkdddd2 <= v2;
      sinkdddd3 <= v3;
      sinkdddd4 <= v4;
   endmethod

   method Action startspit(SpitType spitType, Bit#(16) loops);
      dofns[spittype].do(loops);
   endmethod

endmodule


change to DmaOffsetSize

change to DmaOffsetSize

// This is a fifo implmented with a ring buffer in main memory.
//
// SW->HW version
//  enqueue data in memory
//  update write pointer with portal request
// The hardware side activates when the write pointer is different than
// the read pointer, and copies data into an output BRAM fifo
//
// Software is responsible for knowing where the read pointer is,
// either by explicitly reading it with a portal-request -> portal indication
// or by other means
//
// Configuration.
import Dma::*;

interface RingBuffer;
   method Bool notEmpty();
   method Bool notFull();
   method Action push(Bit#(8) num);
   method Action pop(Bit#(8) num);
   interface Reg#(Bit#(DmaOffsetize)) bufferfirst;
   interface Reg#(Bit#(DmaOffsetSize)) bufferlast;
   interface Reg#(Bool) enable;
   interface RingBufferConfig configifc;
   interface Reg#(DmaPointer) memhandle;
endinterface

interface RingBufferConfig;
   method Action set(Bit#(3) regist, Bit#(32) addr);
   method Bit#(32) get(Bit#(3) regist);
endinterface

module mkRingBuffer(RingBuffer);

   Reg#(Bit#(DmaOffsetSize)) rbufferbase <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) rbufferend <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) rbufferfirst <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) rbufferlast <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) rbuffermask <- mkReg(0);
   Reg#(DmaPointer) rmemhandle <- mkReg(0);
   Reg#(Bool) renable <- mkReg(False);

   interface RingBufferConfig configifc;
   method Action set(Bit#(3) regist, Bit#(32) addr);
      if (regist == 0) rbufferbase <= truncate(addr);
      else if (regist == 1) rbufferend <= truncate(addr);
      else if (regist == 2) rbufferfirst <= truncate(addr);
      else if (regist == 3) rbufferlast <= truncate(addr);
      else if (regist == 4) rbuffermask <= truncate(addr);
      else if (regist == 5) rmemhandle <= truncate(addr);
      else renable <= (addr[0] != 0);
   endmethod

   method Bit#(32) get(Bit#(3) regist);
      if (regist == 0) return (zeroExtend(rbufferbase));
      else if (regist == 1) return (zeroExtend(rbufferend));
      else if (regist == 2) return (zeroExtend(rbufferfirst));
      else if (regist == 3) return (zeroExtend(rbufferlast));
      else if (regist == 4) return (zeroExtend(rbuffermask));
      else if (regist == 5) return (zeroExtend(rmemhandle));
      else return(zeroExtend(pack(renable)));
   endmethod
   endinterface

   method Bool notEmpty();
   return (rbufferfirst != rbufferlast);
   endmethod

   method Bool notFull();
   return (((rbufferfirst + 64) & rbuffermask) != rbufferlast);
   endmethod

   method Action push(Bit#(8) num);
   rbufferfirst <= (rbufferfirst + zeroExtend(num)) & rbuffermask;
   endmethod

   method Action pop(Bit#(8) num);
   rbufferlast <= (rbufferlast + zeroExtend(num)) & rbuffermask;
   endmethod

   interface Reg bufferfirst = rbufferfirst;
   interface Reg bufferlast = rbufferlast;
   interface Reg enable = renable;
   interface Reg memhandle = rmemhandle;

endmodule

// This is a fifo implmented with a ring buffer in main memory.
//
// SW->HW version
//  enqueue data in memory
//  update write pointer with portal request
// The hardware side activates when the write pointer is different than
// the read pointer, and copies data into an output BRAM fifo
//
// Software is responsible for knowing where the read pointer is,
// either by explicitly reading it with a portal-request -> portal indication
// or by other means
//
// Configuration.
import Dma::*;

interface RingBuffer;
   method Bool notEmpty();
   method Bool notFull();
   method Action push(Bit#(8) num);
   method Action pop(Bit#(8) num);
   interface Reg#(Bit#(DmaAddrSize)) bufferfirst;
   interface Reg#(Bit#(DmaAddrSize)) bufferlast;
   interface Reg#(Bool) enable;
   interface RingBufferConfig configifc;
   interface Reg#(DmaPointer) memhandle;
endinterface

interface RingBufferConfig;
   method Action set(Bit#(3) regist, Bit#(32) addr);
   method Bit#(32) get(Bit#(3) regist);
endinterface

module mkRingBuffer(RingBuffer);

   Reg#(Bit#(DmaAddrSize)) rbufferbase <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) rbufferend <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) rbufferfirst <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) rbufferlast <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) rbuffermask <- mkReg(0);
   Reg#(DmaPointer) rmemhandle <- mkReg(0);
   Reg#(Bool) renable <- mkReg(False);

   interface RingBufferConfig configifc;
   method Action set(Bit#(3) regist, Bit#(32) addr);
      if (regist == 0) rbufferbase <= truncate(addr);
      else if (regist == 1) rbufferend <= truncate(addr);
      else if (regist == 2) rbufferfirst <= truncate(addr);
      else if (regist == 3) rbufferlast <= truncate(addr);
      else if (regist == 4) rbuffermask <= truncate(addr);
      else if (regist == 5) rmemhandle <= truncate(addr);
      else renable <= (addr[0] != 0);
   endmethod

   method Bit#(32) get(Bit#(3) regist);
      if (regist == 0) return (zeroExtend(rbufferbase));
      else if (regist == 1) return (zeroExtend(rbufferend));
      else if (regist == 2) return (zeroExtend(rbufferfirst));
      else if (regist == 3) return (zeroExtend(rbufferlast));
      else if (regist == 4) return (zeroExtend(rbuffermask));
      else if (regist == 5) return (zeroExtend(rmemhandle));
      else return(zeroExtend(pack(renable)));
   endmethod
   endinterface

   method Bool notEmpty();
   return (rbufferfirst != rbufferlast);
   endmethod

   method Bool notFull();
   return (((rbufferfirst + 64) & rbuffermask) != rbufferlast);
   endmethod

   method Action push(Bit#(8) num);
   rbufferfirst <= (rbufferfirst + zeroExtend(num)) & rbuffermask;
   endmethod

   method Action pop(Bit#(8) num);
   rbufferlast <= (rbufferlast + zeroExtend(num)) & rbuffermask;
   endmethod

   interface Reg bufferfirst = rbufferfirst;
   interface Reg bufferlast = rbufferlast;
   interface Reg enable = renable;
   interface Reg memhandle = rmemhandle;

endmodule