added idWidth type parameter and mkAxi3Master

// Copyright (c) 2012 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 RegFile::*;
import BRAMFIFO::*;
import FIFO::*;
import FIFOF::*;
import FIFOLevel::*;
import SpecialFIFOs::*;
import AxiClientServer::*;

interface AxiMasterRead#(type busWidth);
   method ActionValue#(Bit#(32)) readAddr();
   method Bit#(8) readBurstLen();
   method Bit#(3) readBurstWidth();
   method Bit#(2) readBurstType();  // drive with 2'b01
   method Bit#(3) readBurstProt(); // drive with 3'b000
   method Bit#(4) readBurstCache(); // drive with 4'b0011
   method Bit#(1) readId();

   method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id);
endinterface

interface AxiMasterWrite#(type busWidth, type busWidthBytes);
   method ActionValue#(Bit#(32)) writeAddr();
   method Bit#(8) writeBurstLen();
   method Bit#(3) writeBurstWidth();
   method Bit#(2) writeBurstType();  // drive with 2'b01
   method Bit#(3) writeBurstProt(); // drive with 3'b000
   method Bit#(4) writeBurstCache(); // drive with 4'b0011
   method Bit#(1) writeId();

   method ActionValue#(Bit#(busWidth)) writeData();
   method Bit#(busWidthBytes) writeDataByteEnable();
   method Bit#(1) writeLastDataBeat(); // last data beat
   method Action writeResponse(Bit#(2) responseCode, Bit#(1) id);
endinterface

interface AxiMaster#(type busWidth, type busWidthBytes);
   interface AxiMasterRead#(busWidth) read;
   interface AxiMasterWrite#(busWidth, busWidthBytes) write;
endinterface

interface Axi3MasterRead#(type busWidth, type idWidth);
   method ActionValue#(Bit#(32)) readAddr();
   method Bit#(4) readBurstLen();
   method Bit#(3) readBurstWidth();
   method Bit#(2) readBurstType();  // drive with 2'b01
   method Bit#(2) readBurstProt(); // drive with 3'b000
   method Bit#(3) readBurstCache(); // drive with 4'b0011
   method Bit#(idWidth) readId();

   method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(idWidth) id);
endinterface

interface Axi3MasterWrite#(type busWidth, type busWidthBytes, type idWidth);
   method ActionValue#(Bit#(32)) writeAddr();
   method Bit#(4) writeBurstLen();
   method Bit#(3) writeBurstWidth();
   method Bit#(2) writeBurstType();  // drive with 2'b01
   method Bit#(2) writeBurstProt(); // drive with 3'b000
   method Bit#(3) writeBurstCache(); // drive with 4'b0011
   method Bit#(idWidth) writeId();

   method ActionValue#(Bit#(busWidth)) writeData();
   method Bit#(busWidthBytes) writeDataByteEnable();
   method Bit#(1) writeLastDataBeat(); // last data beat
   method Action writeResponse(Bit#(2) responseCode, Bit#(idWidth) id);
endinterface

interface Axi3Master#(type busWidth, type busWidthBytes, type idWidth);
   interface Axi3MasterRead#(busWidth, idWidth) read;
   interface Axi3MasterWrite#(busWidth, busWidthBytes, idWidth) write;
endinterface

interface AxiSlaveRead#(type busWidth, type busWidthBytes);
   method Action readAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                          Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache);

   method ActionValue#(Bit#(busWidth)) readData();
   method Bit#(1) last();
   // method Action readResponse(Bit#(2) responseCode);
endinterface

interface AxiSlaveWrite#(type busWidth, type busWidthBytes);
   method Action writeAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                           Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache);
   method Action writeData(Bit#(busWidth) data, Bit#(busWidthBytes) byteEnable, Bit#(1) last);
   method ActionValue#(Bit#(2)) writeResponse();
endinterface

interface AxiSlave#(type busWidth, type busWidthBytes);
   interface AxiSlaveRead#(busWidth, busWidthBytes) read;
   interface AxiSlaveWrite#(busWidth, busWidthBytes) write;
endinterface

interface Axi3SlaveRead#(type busWidth, type busWidthBytes);
   method Action readAddr(Bit#(32) addr, Bit#(4) burstLen, Bit#(3) burstWidth,
                          Bit#(2) burstType, Bit#(2) burstProt, Bit#(3) burstCache, Bit#(12) arid);

   method ActionValue#(Bit#(busWidth)) readData();
   method Bit#(1) last();
   method Bit#(12) rid();
   // method Action readResponse(Bit#(2) responseCode);
endinterface

interface Axi3SlaveWrite#(type busWidth, type busWidthBytes);
   method Action writeAddr(Bit#(32) addr, Bit#(4) burstLen, Bit#(3) burstWidth,
                           Bit#(2) burstType, Bit#(2) burstProt, Bit#(3) burstCache, Bit#(12) awid);
   method Action writeData(Bit#(busWidth) data, Bit#(busWidthBytes) byteEnable, Bit#(1) last);
   method ActionValue#(Bit#(2)) writeResponse();
   method ActionValue#(Bit#(12)) bid();
endinterface

interface Axi3Slave#(type busWidth, type busWidthBytes);
   interface Axi3SlaveRead#(busWidth, busWidthBytes) read;
   interface Axi3SlaveWrite#(busWidth, busWidthBytes) write;
endinterface

interface AxiMasterServer#(type busWidth, type busWidthBytes, type tagSize);
   method Action readAddr(Bit#(32) addr, Bit#(8) numWords);
   method Action readAddrTagged(Bit#(32) addr, Bit#(8) numWords, Bit#(tagSize) tag);
   method ActionValue#(Bit#(busWidth)) readData();
   method Bit#(tagSize) readTag();

   method Action writeAddr(Bit#(32) addr, Bit#(8) numWords);
   method Action writeData(Bit#(busWidth) data);
   method ActionValue#(Bit#(2)) writeResponse();

   interface AxiMaster#(busWidth,busWidthBytes) axi;
endinterface

typedef struct {
    Bit#(32) addr;
    Bit#(8) numWords;
} AddrBurst deriving (Bits);

module mkAxiMasterServer(AxiMasterServer#(busWidth,busWidthBytes,tagSize)) provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));
   Reg#(Bit#(32)) wAddrReg <- mkReg(0);
   Reg#(Bit#(1)) writeIdReg <- mkReg(0);
   Reg#(Bit#(1)) readIdReg <- mkReg(0);
   FIFOF#(Bit#(busWidth)) wfifo <- mkSizedBRAMFIFOF(32);
   FIFOF#(Bit#(2)) bfifo <- mkSizedBRAMFIFOF(32);
   Reg#(Bit#(8)) wBurstCountReg <- mkReg(0);
   Reg#(Bool) wAddressPresented <- mkReg(False);

   FIFOF#(AddrBurst) raddrFifo <- mkSizedBypassFIFOF(4);
   FIFOF#(Bit#(tagSize)) tagFifo <- mkSizedFIFOF(4);
   //FIFOF#(AddrBurst) raddrFifo <- mkSizedBRAMFIFOF(8);
   let rfifoDepth = 1024;
   FIFOF#(Bit#(busWidth)) rfifo <- mkSizedBRAMFIFOF(rfifoDepth);
   Reg#(Bit#(11)) rfifoWordsAvail <- mkReg(rfifoDepth);
   PulseWire enqPulse <- mkPulseWire();
   PulseWire deqPulse <- mkPulseWire();
   Wire#(Bit#(8)) readCount <- mkDWire(0);

   rule updateWordsAvailCount;
      let avail = rfifoWordsAvail;
      if (enqPulse)
          avail = avail - extend(readCount);
      if (deqPulse)
          avail = avail + 1;
      rfifoWordsAvail <= avail;
   endrule

   method Action readAddr(Bit#(32) addr, Bit#(8) numWords);
       //$display("readAddr addr %h burstCountReg %d", addr, numWords);
       raddrFifo.enq(AddrBurst { addr: addr, numWords: numWords});
       tagFifo.enq(0);
   endmethod

   method Action readAddrTagged(Bit#(32) addr, Bit#(8) numWords, Bit#(tagSize) tag);
       //$display("readAddr addr %h burstCountReg %d", addr, numWords);
       raddrFifo.enq(AddrBurst { addr: addr, numWords: numWords});
       tagFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(busWidth)) readData() if (rfifo.notEmpty);
       //$display("axiMaster.readData %h", rfifo.first);
       deqPulse.send;
       rfifo.deq;
       tagFifo.deq;
       return rfifo.first;
   endmethod

   method Bit#(tagSize) readTag();
       return tagFifo.first;
   endmethod

   method Action writeAddr(Bit#(32) addr, Bit#(8) numWords) if (wBurstCountReg == 0);
       wAddrReg <= addr;
       wBurstCountReg <= numWords;
       wAddressPresented <= False;
   endmethod

   method Action writeData(Bit#(busWidth) data) if (wfifo.notFull);
       wfifo.enq(data);
   endmethod
   method ActionValue#(Bit#(2)) writeResponse() if (bfifo.notEmpty);
       bfifo.deq;
       return bfifo.first;
   endmethod

   interface AxiMaster axi;
       interface AxiMasterWrite write;
           method ActionValue#(Bit#(32)) writeAddr() if (wBurstCountReg != 0 && !wAddressPresented);
               wAddressPresented <= True;
               writeIdReg <= writeIdReg + 1;
               return wAddrReg;
           endmethod
           method Bit#(8) writeBurstLen();
               return wBurstCountReg-1;
           endmethod
           method Bit#(3) writeBurstWidth();
               if (valueOf(busWidth) == 32)
                   return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
               else if (valueOf(busWidth) == 64)
                   return 3'b011;
               else
                   return 3'b100;
           endmethod
           method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
               return 2'b01; // increment address
           endmethod
           method Bit#(3) writeBurstProt(); // drive with 3'b000
               return 3'b000;
           endmethod
           method Bit#(4) writeBurstCache(); // drive with 4'b0011
               return 4'b0011;
           endmethod
           method Bit#(1) writeId();
               return writeIdReg;
           endmethod

           method ActionValue#(Bit#(busWidth)) writeData() if (wBurstCountReg != 0 && wfifo.notEmpty);
               wBurstCountReg <= wBurstCountReg - 1;

               let d = wfifo.first;
               wfifo.deq;
               return d;
           endmethod
           method Bit#(busWidthBytes) writeDataByteEnable();
               return maxBound;
           endmethod
           method Bit#(1) writeLastDataBeat(); // last data beat
               return (wBurstCountReg == 8'd1) ? 1'b1 : 1'b0;
           endmethod

           method Action writeResponse(Bit#(2) responseCode, Bit#(1) id) if (bfifo.notFull);
               if (responseCode != 0)
                   bfifo.enq(responseCode);
           endmethod
       endinterface

       interface AxiMasterRead read;
           method ActionValue#(Bit#(32)) readAddr() if (extend(unpack(raddrFifo.first.numWords)) <= rfifoWordsAvail);
               enqPulse.send;
               readCount <= raddrFifo.first.numWords;
               raddrFifo.deq();
               readIdReg <= readIdReg + 1;
               return raddrFifo.first().addr;
           endmethod
           method Bit#(8) readBurstLen();
               return raddrFifo.first().numWords-1;
           endmethod
           method Bit#(3) readBurstWidth();
               if (valueOf(busWidth) == 32)
                   return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
               else if (valueOf(busWidth) == 64)
                   return 3'b011;
               else
                   return 3'b100;
           endmethod
           method Bit#(2) readBurstType();  // drive with 2'b01
               return 2'b01;
           endmethod
           method Bit#(3) readBurstProt(); // drive with 3'b000
               return 3'b000;
           endmethod
           method Bit#(4) readBurstCache(); // drive with 4'b0011
               return 4'b0011;
           endmethod
           method Bit#(1) readId();
               return readIdReg;
           endmethod
           method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id) if (rfifo.notFull);
	       //$display("axi.read.readData %h bc %d", data, rBurstCountReg);
               rfifo.enq(data);
           endmethod
       endinterface
   endinterface
endmodule

module mkNullAxiMaster(AxiMaster#(busWidth,busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));
   interface AxiMasterWrite write;
       method ActionValue#(Bit#(32)) writeAddr() if (False);
           return 0;
       endmethod
       method Bit#(8) writeBurstLen();
           return 0;
       endmethod
       method Bit#(3) writeBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
           return 2'b01; // increment address
       endmethod
       method Bit#(3) writeBurstProt(); // drive with 3'b000
           return 3'b000;
       endmethod
       method Bit#(4) writeBurstCache(); // drive with 4'b0011
           return 4'b0011;
       endmethod
       method Bit#(1) writeId();
           return 0;
       endmethod

       method ActionValue#(Bit#(busWidth)) writeData();
           return 0;
       endmethod
       method Bit#(busWidthBytes) writeDataByteEnable();
           return maxBound;
       endmethod
       method Bit#(1) writeLastDataBeat(); // last data beat
           return 0;
       endmethod

       method Action writeResponse(Bit#(2) responseCode, Bit#(1) id);
       endmethod
   endinterface

   interface AxiMasterRead read;
       method ActionValue#(Bit#(32)) readAddr() if (False);
           return 0;
       endmethod
       method Bit#(8) readBurstLen();
           return 0;
       endmethod
       method Bit#(3) readBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) readBurstType();  // drive with 2'b01
           return 2'b01;
       endmethod
       method Bit#(3) readBurstProt(); // drive with 3'b000
           return 3'b000;
       endmethod
       method Bit#(4) readBurstCache(); // drive with 4'b0011
           return 4'b0011;
       endmethod
       method Bit#(1) readId();
           return 0;
       endmethod
       method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id);
       endmethod
   endinterface
endmodule

module mkNullAxi3Master(Axi3Master#(busWidth,busWidthBytes,idWidth)) provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));
   interface Axi3MasterWrite write;
       method ActionValue#(Bit#(32)) writeAddr() if (False);
           return 0;
       endmethod
       method Bit#(4) writeBurstLen();
           return 0;
       endmethod
       method Bit#(3) writeBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
           return 2'b01; // increment address
       endmethod
       method Bit#(2) writeBurstProt(); // drive with 3'b000
           return 2'b00;
       endmethod
       method Bit#(3) writeBurstCache(); // drive with 4'b0011
           return 3'b011;
       endmethod
       method Bit#(idWidth) writeId();
           return 0;
       endmethod

       method ActionValue#(Bit#(busWidth)) writeData();
           return 0;
       endmethod
       method Bit#(busWidthBytes) writeDataByteEnable();
           return maxBound;
       endmethod
       method Bit#(1) writeLastDataBeat(); // last data beat
           return 0;
       endmethod

       method Action writeResponse(Bit#(2) responseCode, Bit#(idWidth) id);
       endmethod
   endinterface

   interface Axi3MasterRead read;
       method ActionValue#(Bit#(32)) readAddr() if (False);
           return 0;
       endmethod
       method Bit#(4) readBurstLen();
           return 0;
       endmethod
       method Bit#(3) readBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) readBurstType();  // drive with 2'b01
           return 2'b01;
       endmethod
       method Bit#(2) readBurstProt(); // drive with 3'b000
           return 2'b00;
       endmethod
       method Bit#(3) readBurstCache(); // drive with 4'b0011
           return 3'b011;
       endmethod
       method Bit#(idWidth) readId();
           return 0;
       endmethod
       method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(idWidth) id);
       endmethod
   endinterface
endmodule

module mkAxiSlaveFromRegFile#(RegFile#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
                             (AxiSlave#(busWidth, busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes),
                                                                           Add#(nz, regFileBusWidth, 32));
    Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
    Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
    Reg#(Bit#(8)) readBurstCountReg <- mkReg(0);
    Reg#(Bit#(8)) writeBurstCountReg <- mkReg(0);
    FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();

    Bool verbose = False;
    interface AxiSlaveRead read;
        method Action readAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                               Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache) if (readBurstCountReg == 0);
            if (verbose) $display("axiSlave.read.readAddr %h bc %d", addr, burstLen+1);
            readAddrReg <= truncate(addr/fromInteger(valueOf(busWidthBytes)));
            readBurstCountReg <= burstLen+1;
        endmethod

        method ActionValue#(Bit#(busWidth)) readData() if (readBurstCountReg > 0);
            let data = rf.sub(readAddrReg);
            if (verbose) $display("axiSlave.read.readData %h %h %d", readAddrReg, data, readBurstCountReg);
            readBurstCountReg <= readBurstCountReg - 1;
            readAddrReg <= readAddrReg + 1;
            return data;
        endmethod
        method Bit#(1) last();
            return (readBurstCountReg == 1) ? 1 : 0;
        endmethod
    endinterface

    interface AxiSlaveWrite write;
       method Action writeAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                               Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache) if (writeBurstCountReg == 0);
           if (verbose) $display("axiSlave.write.writeAddr %h bc %d", addr, burstLen+1);
           writeAddrReg <= truncate(addr/fromInteger(valueOf(busWidthBytes)));
           writeBurstCountReg <= burstLen+1;
       endmethod

       method Action writeData(Bit#(busWidth) data, Bit#(busWidthBytes) byteEnable, Bit#(1) last) if (writeBurstCountReg > 0);
           if (verbose) $display("writeData %h %h %d", writeAddrReg, data, writeBurstCountReg);
           rf.upd(writeAddrReg, data);
           writeAddrReg <= writeAddrReg + 1;
           writeBurstCountReg <= writeBurstCountReg - 1;
            if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, data, writeBurstCountReg);
           if (writeBurstCountReg == 1)
               writeRespFifo.enq(0);
       endmethod
       method ActionValue#(Bit#(2)) writeResponse();
           writeRespFifo.deq;
           return writeRespFifo.first;
       endmethod
    endinterface
endmodule

module mkAxiSlaveRegFile(AxiSlave#(busWidth, busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes));
       RegFile#(Bit#(21), Bit#(busWidth)) rf <- mkRegFileFull();
       AxiSlave#(busWidth, busWidthBytes) axiSlave <- mkAxiSlaveFromRegFile(rf);
       return axiSlave;
endmodule

module mkAxiSlaveRegFileLoad#(String fileName)(AxiSlave#(busWidth, busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes));
       RegFile#(Bit#(21), Bit#(busWidth)) rf <- mkRegFileFullLoad(fileName);
       AxiSlave#(busWidth, busWidthBytes) axiSlave <- mkAxiSlaveFromRegFile(rf);
       return axiSlave;
endmodule

module mkMasterSlaveConnection#(AxiMasterWrite#(busWidth, busWidthBytes) axiw,
                                AxiMasterRead#(busWidth) axir,
                                AxiSlave#(busWidth, busWidthBytes) axiSlave)
                                ();

    Reg#(Bit#(8)) writeBurstCountReg <- mkReg(0);
    Bool verbose = False;

    rule readAddr;
        Bit#(32) addr <-axir.readAddr;
        let burstLen = axir.readBurstLen;
        let burstWidth = axir.readBurstWidth;
        let burstType = axir.readBurstType;
        let burstProt = axir.readBurstProt;
        let burstCache = axir.readBurstCache;
        axiSlave.read.readAddr(addr, burstLen, burstWidth, burstType, burstProt, burstCache);
	if (verbose) $display("        MasterSlaveConnection.readAddr %h %d", addr, burstLen+1);
    endrule
    rule readData;
        let data <- axiSlave.read.readData();
        axir.readData(data, 2'b00, 0, 0);
        if (verbose) $display("        MasterSlaveConnection.readData %h", data);
    endrule
    rule writeAddr;
        Bit#(32) addr <- axiw.writeAddr;
        let burstLen = axiw.writeBurstLen;
        let burstWidth = axiw.writeBurstWidth;
        let burstType = axiw.writeBurstType;
        let burstProt = axiw.writeBurstProt;
        let burstCache = axiw.writeBurstCache;
        axiSlave.write.writeAddr(addr, burstLen, burstWidth, burstType, burstProt, burstCache);
        if (verbose) $display("        MasterSlaveConnection.writeAddr %h %d", addr, burstLen+1);
    endrule
    rule writeData;
        let data <- axiw.writeData;
        let byteEnable = axiw.writeDataByteEnable;
        let last = axiw.writeLastDataBeat;
        axiSlave.write.writeData(data, byteEnable, last);
        if (verbose) $display("        MasterSlaveConnection.writeData %h", data);
    endrule
    rule writeResponse;
        let response <- axiSlave.write.writeResponse();
        axiw.writeResponse(response, 0);
    endrule
endmodule

module mkAxi3Master#(Axi3Client#(busWidth,busWidthBytes,idWidth) client)(Axi3Master#(busWidth,busWidthBytes,idWidth))
	 provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));

    Wire#(Axi3ReadRequest#(idWidth))                      wReadRequest <- mkDWire(unpack(0));
    Wire#(Axi3WriteRequest#(idWidth))                     wWriteRequest <- mkDWire(unpack(0));
    Wire#(Axi3WriteData#(busWidth,busWidthBytes,idWidth)) wWriteData <- mkDWire(unpack(0));

    interface Axi3MasterWrite write;
	method ActionValue#(Bit#(32)) writeAddr() if (False);
	    let r <- client.write.address();
	    wWriteRequest <= r;
	    return r.address;
	endmethod
	method Bit#(4) writeBurstLen();
	    return wWriteRequest.burstLen;
	endmethod
	method Bit#(3) writeBurstWidth();
	    if (valueOf(busWidth) == 32)
		return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
	    else if (valueOf(busWidth) == 64)
		return 3'b011;
	    else
		return 3'b100;
	endmethod
	method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
	    return 2'b01; // increment address
	endmethod
	method Bit#(2) writeBurstProt(); // drive with 3'b000
	    return 2'b000;
	endmethod
	method Bit#(3) writeBurstCache(); // drive with 4'b0011
	    return 3'b0011;
	endmethod
	method Bit#(idWidth) writeId();
	    return wWriteRequest.id;
	endmethod

	method ActionValue#(Bit#(busWidth)) writeData();
	    let d <- client.write.data();
	    wWriteData <= d;
	    return d.data;
	endmethod
	method Bit#(busWidthBytes) writeDataByteEnable();
	    return maxBound;
	endmethod
	method Bit#(1) writeLastDataBeat(); // last data beat
	    return wWriteData.last;
	endmethod

	method Action writeResponse(Bit#(2) responseCode, Bit#(idWidth) id);
	    client.write.response(Axi3WriteResponse { response: responseCode, id: id});
	endmethod
    endinterface

    interface Axi3MasterRead read;
	method ActionValue#(Bit#(32)) readAddr();
	    let r <- client.read.address();
	    wReadRequest <= r;
	    return r.address;
	endmethod
	method Bit#(4) readBurstLen();
	    return wReadRequest.burstLen;
	endmethod
	method Bit#(3) readBurstWidth();
	    if (valueOf(busWidth) == 32)
		return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
	    else if (valueOf(busWidth) == 64)
		return 3'b011;
	    else
		return 3'b100;
	endmethod
	method Bit#(2) readBurstType();  // drive with 2'b01
	    return 2'b01;
	endmethod
	method Bit#(2) readBurstProt(); // drive with 3'b000
	    return 2'b000;
	endmethod
	method Bit#(3) readBurstCache(); // drive with 4'b0011
	    return 3'b0011;
	endmethod
	method Bit#(idWidth) readId();
	    return wReadRequest.id;
	endmethod
	method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(idWidth) id);
	    client.read.data(Axi3ReadResponse { data: data, resp: resp, last: last, id: id});
	endmethod
   endinterface
endmodule

// Copyright (c) 2012 Nokia, Inc.

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

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

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

import RegFile::*;
import BRAMFIFO::*;
import FIFO::*;
import FIFOF::*;
import FIFOLevel::*;
import SpecialFIFOs::*;

interface AxiMasterRead#(type busWidth);
   method ActionValue#(Bit#(32)) readAddr();
   method Bit#(8) readBurstLen();
   method Bit#(3) readBurstWidth();
   method Bit#(2) readBurstType();  // drive with 2'b01
   method Bit#(3) readBurstProt(); // drive with 3'b000
   method Bit#(4) readBurstCache(); // drive with 4'b0011
   method Bit#(1) readId();

   method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id);
endinterface

interface AxiMasterWrite#(type busWidth, type busWidthBytes);
   method ActionValue#(Bit#(32)) writeAddr();
   method Bit#(8) writeBurstLen();
   method Bit#(3) writeBurstWidth();
   method Bit#(2) writeBurstType();  // drive with 2'b01
   method Bit#(3) writeBurstProt(); // drive with 3'b000
   method Bit#(4) writeBurstCache(); // drive with 4'b0011
   method Bit#(1) writeId();

   method ActionValue#(Bit#(busWidth)) writeData();
   method Bit#(busWidthBytes) writeDataByteEnable();
   method Bit#(1) writeLastDataBeat(); // last data beat
   method Action writeResponse(Bit#(2) responseCode, Bit#(1) id);
endinterface

interface AxiMaster#(type busWidth, type busWidthBytes);
   interface AxiMasterRead#(busWidth) read;
   interface AxiMasterWrite#(busWidth, busWidthBytes) write;
endinterface

interface Axi3MasterRead#(type busWidth);
   method ActionValue#(Bit#(32)) readAddr();
   method Bit#(4) readBurstLen();
   method Bit#(3) readBurstWidth();
   method Bit#(2) readBurstType();  // drive with 2'b01
   method Bit#(2) readBurstProt(); // drive with 3'b000
   method Bit#(3) readBurstCache(); // drive with 4'b0011
   method Bit#(1) readId();

   method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id);
endinterface

interface Axi3MasterWrite#(type busWidth, type busWidthBytes);
   method ActionValue#(Bit#(32)) writeAddr();
   method Bit#(4) writeBurstLen();
   method Bit#(3) writeBurstWidth();
   method Bit#(2) writeBurstType();  // drive with 2'b01
   method Bit#(2) writeBurstProt(); // drive with 3'b000
   method Bit#(3) writeBurstCache(); // drive with 4'b0011
   method Bit#(1) writeId();

   method ActionValue#(Bit#(busWidth)) writeData();
   method Bit#(busWidthBytes) writeDataByteEnable();
   method Bit#(1) writeLastDataBeat(); // last data beat
   method Action writeResponse(Bit#(2) responseCode, Bit#(1) id);
endinterface

interface Axi3Master#(type busWidth, type busWidthBytes);
   interface Axi3MasterRead#(busWidth) read;
   interface Axi3MasterWrite#(busWidth, busWidthBytes) write;
endinterface

interface AxiSlaveRead#(type busWidth, type busWidthBytes);
   method Action readAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                          Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache);

   method ActionValue#(Bit#(busWidth)) readData();
   method Bit#(1) last();
   // method Action readResponse(Bit#(2) responseCode);
endinterface

interface AxiSlaveWrite#(type busWidth, type busWidthBytes);
   method Action writeAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                           Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache);
   method Action writeData(Bit#(busWidth) data, Bit#(busWidthBytes) byteEnable, Bit#(1) last);
   method ActionValue#(Bit#(2)) writeResponse();
endinterface

interface AxiSlave#(type busWidth, type busWidthBytes);
   interface AxiSlaveRead#(busWidth, busWidthBytes) read;
   interface AxiSlaveWrite#(busWidth, busWidthBytes) write;
endinterface

interface Axi3SlaveRead#(type busWidth, type busWidthBytes);
   method Action readAddr(Bit#(32) addr, Bit#(4) burstLen, Bit#(3) burstWidth,
                          Bit#(2) burstType, Bit#(2) burstProt, Bit#(3) burstCache, Bit#(12) arid);

   method ActionValue#(Bit#(busWidth)) readData();
   method Bit#(1) last();
   method Bit#(12) rid();
   // method Action readResponse(Bit#(2) responseCode);
endinterface

interface Axi3SlaveWrite#(type busWidth, type busWidthBytes);
   method Action writeAddr(Bit#(32) addr, Bit#(4) burstLen, Bit#(3) burstWidth,
                           Bit#(2) burstType, Bit#(2) burstProt, Bit#(3) burstCache, Bit#(12) awid);
   method Action writeData(Bit#(busWidth) data, Bit#(busWidthBytes) byteEnable, Bit#(1) last);
   method ActionValue#(Bit#(2)) writeResponse();
   method ActionValue#(Bit#(12)) bid();
endinterface

interface Axi3Slave#(type busWidth, type busWidthBytes);
   interface Axi3SlaveRead#(busWidth, busWidthBytes) read;
   interface Axi3SlaveWrite#(busWidth, busWidthBytes) write;
endinterface

interface AxiMasterServer#(type busWidth, type busWidthBytes, type tagSize);
   method Action readAddr(Bit#(32) addr, Bit#(8) numWords);
   method Action readAddrTagged(Bit#(32) addr, Bit#(8) numWords, Bit#(tagSize) tag);
   method ActionValue#(Bit#(busWidth)) readData();
   method Bit#(tagSize) readTag();

   method Action writeAddr(Bit#(32) addr, Bit#(8) numWords);
   method Action writeData(Bit#(busWidth) data);
   method ActionValue#(Bit#(2)) writeResponse();

   interface AxiMaster#(busWidth,busWidthBytes) axi;
endinterface

typedef struct {
    Bit#(32) addr;
    Bit#(8) numWords;
} AddrBurst deriving (Bits);

module mkAxiMasterServer(AxiMasterServer#(busWidth,busWidthBytes,tagSize)) provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));
   Reg#(Bit#(32)) wAddrReg <- mkReg(0);
   Reg#(Bit#(1)) writeIdReg <- mkReg(0);
   Reg#(Bit#(1)) readIdReg <- mkReg(0);
   FIFOF#(Bit#(busWidth)) wfifo <- mkSizedBRAMFIFOF(32);
   FIFOF#(Bit#(2)) bfifo <- mkSizedBRAMFIFOF(32);
   Reg#(Bit#(8)) wBurstCountReg <- mkReg(0);
   Reg#(Bool) wAddressPresented <- mkReg(False);

   FIFOF#(AddrBurst) raddrFifo <- mkSizedBypassFIFOF(4);
   FIFOF#(Bit#(tagSize)) tagFifo <- mkSizedFIFOF(4);
   //FIFOF#(AddrBurst) raddrFifo <- mkSizedBRAMFIFOF(8);
   let rfifoDepth = 1024;
   FIFOF#(Bit#(busWidth)) rfifo <- mkSizedBRAMFIFOF(rfifoDepth);
   Reg#(Bit#(11)) rfifoWordsAvail <- mkReg(rfifoDepth);
   PulseWire enqPulse <- mkPulseWire();
   PulseWire deqPulse <- mkPulseWire();
   Wire#(Bit#(8)) readCount <- mkDWire(0);

   rule updateWordsAvailCount;
      let avail = rfifoWordsAvail;
      if (enqPulse)
          avail = avail - extend(readCount);
      if (deqPulse)
          avail = avail + 1;
      rfifoWordsAvail <= avail;
   endrule

   method Action readAddr(Bit#(32) addr, Bit#(8) numWords);
       //$display("readAddr addr %h burstCountReg %d", addr, numWords);
       raddrFifo.enq(AddrBurst { addr: addr, numWords: numWords});
       tagFifo.enq(0);
   endmethod

   method Action readAddrTagged(Bit#(32) addr, Bit#(8) numWords, Bit#(tagSize) tag);
       //$display("readAddr addr %h burstCountReg %d", addr, numWords);
       raddrFifo.enq(AddrBurst { addr: addr, numWords: numWords});
       tagFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(busWidth)) readData() if (rfifo.notEmpty);
       //$display("axiMaster.readData %h", rfifo.first);
       deqPulse.send;
       rfifo.deq;
       tagFifo.deq;
       return rfifo.first;
   endmethod

   method Bit#(tagSize) readTag();
       return tagFifo.first;
   endmethod

   method Action writeAddr(Bit#(32) addr, Bit#(8) numWords) if (wBurstCountReg == 0);
       wAddrReg <= addr;
       wBurstCountReg <= numWords;
       wAddressPresented <= False;
   endmethod

   method Action writeData(Bit#(busWidth) data) if (wfifo.notFull);
       wfifo.enq(data);
   endmethod
   method ActionValue#(Bit#(2)) writeResponse() if (bfifo.notEmpty);
       bfifo.deq;
       return bfifo.first;
   endmethod

   interface AxiMaster axi;
       interface AxiMasterWrite write;
           method ActionValue#(Bit#(32)) writeAddr() if (wBurstCountReg != 0 && !wAddressPresented);
               wAddressPresented <= True;
               writeIdReg <= writeIdReg + 1;
               return wAddrReg;
           endmethod
           method Bit#(8) writeBurstLen();
               return wBurstCountReg-1;
           endmethod
           method Bit#(3) writeBurstWidth();
               if (valueOf(busWidth) == 32)
                   return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
               else if (valueOf(busWidth) == 64)
                   return 3'b011;
               else
                   return 3'b100;
           endmethod
           method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
               return 2'b01; // increment address
           endmethod
           method Bit#(3) writeBurstProt(); // drive with 3'b000
               return 3'b000;
           endmethod
           method Bit#(4) writeBurstCache(); // drive with 4'b0011
               return 4'b0011;
           endmethod
           method Bit#(1) writeId();
               return writeIdReg;
           endmethod

           method ActionValue#(Bit#(busWidth)) writeData() if (wBurstCountReg != 0 && wfifo.notEmpty);
               wBurstCountReg <= wBurstCountReg - 1;

               let d = wfifo.first;
               wfifo.deq;
               return d;
           endmethod
           method Bit#(busWidthBytes) writeDataByteEnable();
               return maxBound;
           endmethod
           method Bit#(1) writeLastDataBeat(); // last data beat
               return (wBurstCountReg == 8'd1) ? 1'b1 : 1'b0;
           endmethod

           method Action writeResponse(Bit#(2) responseCode, Bit#(1) id) if (bfifo.notFull);
               if (responseCode != 0)
                   bfifo.enq(responseCode);
           endmethod
       endinterface

       interface AxiMasterRead read;
           method ActionValue#(Bit#(32)) readAddr() if (extend(unpack(raddrFifo.first.numWords)) <= rfifoWordsAvail);
               enqPulse.send;
               readCount <= raddrFifo.first.numWords;
               raddrFifo.deq();
               readIdReg <= readIdReg + 1;
               return raddrFifo.first().addr;
           endmethod
           method Bit#(8) readBurstLen();
               return raddrFifo.first().numWords-1;
           endmethod
           method Bit#(3) readBurstWidth();
               if (valueOf(busWidth) == 32)
                   return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
               else if (valueOf(busWidth) == 64)
                   return 3'b011;
               else
                   return 3'b100;
           endmethod
           method Bit#(2) readBurstType();  // drive with 2'b01
               return 2'b01;
           endmethod
           method Bit#(3) readBurstProt(); // drive with 3'b000
               return 3'b000;
           endmethod
           method Bit#(4) readBurstCache(); // drive with 4'b0011
               return 4'b0011;
           endmethod
           method Bit#(1) readId();
               return readIdReg;
           endmethod
           method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id) if (rfifo.notFull);
	       //$display("axi.read.readData %h bc %d", data, rBurstCountReg);
               rfifo.enq(data);
           endmethod
       endinterface
   endinterface
endmodule

module mkNullAxiMaster(AxiMaster#(busWidth,busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));
   interface AxiMasterWrite write;
       method ActionValue#(Bit#(32)) writeAddr() if (False);
           return 0;
       endmethod
       method Bit#(8) writeBurstLen();
           return 0;
       endmethod
       method Bit#(3) writeBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
           return 2'b01; // increment address
       endmethod
       method Bit#(3) writeBurstProt(); // drive with 3'b000
           return 3'b000;
       endmethod
       method Bit#(4) writeBurstCache(); // drive with 4'b0011
           return 4'b0011;
       endmethod
       method Bit#(1) writeId();
           return 0;
       endmethod

       method ActionValue#(Bit#(busWidth)) writeData();
           return 0;
       endmethod
       method Bit#(busWidthBytes) writeDataByteEnable();
           return maxBound;
       endmethod
       method Bit#(1) writeLastDataBeat(); // last data beat
           return 0;
       endmethod

       method Action writeResponse(Bit#(2) responseCode, Bit#(1) id);
       endmethod
   endinterface

   interface AxiMasterRead read;
       method ActionValue#(Bit#(32)) readAddr() if (False);
           return 0;
       endmethod
       method Bit#(8) readBurstLen();
           return 0;
       endmethod
       method Bit#(3) readBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) readBurstType();  // drive with 2'b01
           return 2'b01;
       endmethod
       method Bit#(3) readBurstProt(); // drive with 3'b000
           return 3'b000;
       endmethod
       method Bit#(4) readBurstCache(); // drive with 4'b0011
           return 4'b0011;
       endmethod
       method Bit#(1) readId();
           return 0;
       endmethod
       method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id);
       endmethod
   endinterface
endmodule

module mkNullAxi3Master(Axi3Master#(busWidth,busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes),Add#(1,a,busWidth));
   interface Axi3MasterWrite write;
       method ActionValue#(Bit#(32)) writeAddr() if (False);
           return 0;
       endmethod
       method Bit#(4) writeBurstLen();
           return 0;
       endmethod
       method Bit#(3) writeBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) writeBurstType();  // drive with 2'b01 increment address
           return 2'b01; // increment address
       endmethod
       method Bit#(2) writeBurstProt(); // drive with 3'b000
           return 2'b00;
       endmethod
       method Bit#(3) writeBurstCache(); // drive with 4'b0011
           return 3'b011;
       endmethod
       method Bit#(1) writeId();
           return 0;
       endmethod

       method ActionValue#(Bit#(busWidth)) writeData();
           return 0;
       endmethod
       method Bit#(busWidthBytes) writeDataByteEnable();
           return maxBound;
       endmethod
       method Bit#(1) writeLastDataBeat(); // last data beat
           return 0;
       endmethod

       method Action writeResponse(Bit#(2) responseCode, Bit#(1) id);
       endmethod
   endinterface

   interface Axi3MasterRead read;
       method ActionValue#(Bit#(32)) readAddr() if (False);
           return 0;
       endmethod
       method Bit#(4) readBurstLen();
           return 0;
       endmethod
       method Bit#(3) readBurstWidth();
           if (valueOf(busWidth) == 32)
               return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
           else if (valueOf(busWidth) == 64)
               return 3'b011;
           else
               return 3'b100;
       endmethod
       method Bit#(2) readBurstType();  // drive with 2'b01
           return 2'b01;
       endmethod
       method Bit#(2) readBurstProt(); // drive with 3'b000
           return 2'b00;
       endmethod
       method Bit#(3) readBurstCache(); // drive with 4'b0011
           return 3'b011;
       endmethod
       method Bit#(1) readId();
           return 0;
       endmethod
       method Action readData(Bit#(busWidth) data, Bit#(2) resp, Bit#(1) last, Bit#(1) id);
       endmethod
   endinterface
endmodule

module mkAxiSlaveFromRegFile#(RegFile#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
                             (AxiSlave#(busWidth, busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes),
                                                                           Add#(nz, regFileBusWidth, 32));
    Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
    Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
    Reg#(Bit#(8)) readBurstCountReg <- mkReg(0);
    Reg#(Bit#(8)) writeBurstCountReg <- mkReg(0);
    FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();

    Bool verbose = False;
    interface AxiSlaveRead read;
        method Action readAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                               Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache) if (readBurstCountReg == 0);
            if (verbose) $display("axiSlave.read.readAddr %h bc %d", addr, burstLen+1);
            readAddrReg <= truncate(addr/fromInteger(valueOf(busWidthBytes)));
            readBurstCountReg <= burstLen+1;
        endmethod

        method ActionValue#(Bit#(busWidth)) readData() if (readBurstCountReg > 0);
            let data = rf.sub(readAddrReg);
            if (verbose) $display("axiSlave.read.readData %h %h %d", readAddrReg, data, readBurstCountReg);
            readBurstCountReg <= readBurstCountReg - 1;
            readAddrReg <= readAddrReg + 1;
            return data;
        endmethod
        method Bit#(1) last();
            return (readBurstCountReg == 1) ? 1 : 0;
        endmethod
    endinterface

    interface AxiSlaveWrite write;
       method Action writeAddr(Bit#(32) addr, Bit#(8) burstLen, Bit#(3) burstWidth,
                               Bit#(2) burstType, Bit#(3) burstProt, Bit#(4) burstCache) if (writeBurstCountReg == 0);
           if (verbose) $display("axiSlave.write.writeAddr %h bc %d", addr, burstLen+1);
           writeAddrReg <= truncate(addr/fromInteger(valueOf(busWidthBytes)));
           writeBurstCountReg <= burstLen+1;
       endmethod

       method Action writeData(Bit#(busWidth) data, Bit#(busWidthBytes) byteEnable, Bit#(1) last) if (writeBurstCountReg > 0);
           if (verbose) $display("writeData %h %h %d", writeAddrReg, data, writeBurstCountReg);
           rf.upd(writeAddrReg, data);
           writeAddrReg <= writeAddrReg + 1;
           writeBurstCountReg <= writeBurstCountReg - 1;
            if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, data, writeBurstCountReg);
           if (writeBurstCountReg == 1)
               writeRespFifo.enq(0);
       endmethod
       method ActionValue#(Bit#(2)) writeResponse();
           writeRespFifo.deq;
           return writeRespFifo.first;
       endmethod
    endinterface
endmodule

module mkAxiSlaveRegFile(AxiSlave#(busWidth, busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes));
       RegFile#(Bit#(21), Bit#(busWidth)) rf <- mkRegFileFull();
       AxiSlave#(busWidth, busWidthBytes) axiSlave <- mkAxiSlaveFromRegFile(rf);
       return axiSlave;
endmodule

module mkAxiSlaveRegFileLoad#(String fileName)(AxiSlave#(busWidth, busWidthBytes)) provisos(Div#(busWidth,8,busWidthBytes));
       RegFile#(Bit#(21), Bit#(busWidth)) rf <- mkRegFileFullLoad(fileName);
       AxiSlave#(busWidth, busWidthBytes) axiSlave <- mkAxiSlaveFromRegFile(rf);
       return axiSlave;
endmodule

module mkMasterSlaveConnection#(AxiMasterWrite#(busWidth, busWidthBytes) axiw,
                                AxiMasterRead#(busWidth) axir,
                                AxiSlave#(busWidth, busWidthBytes) axiSlave)
                                ();

    Reg#(Bit#(8)) writeBurstCountReg <- mkReg(0);
    Bool verbose = False;

    rule readAddr;
        Bit#(32) addr <-axir.readAddr;
        let burstLen = axir.readBurstLen;
        let burstWidth = axir.readBurstWidth;
        let burstType = axir.readBurstType;
        let burstProt = axir.readBurstProt;
        let burstCache = axir.readBurstCache;
        axiSlave.read.readAddr(addr, burstLen, burstWidth, burstType, burstProt, burstCache);
	if (verbose) $display("        MasterSlaveConnection.readAddr %h %d", addr, burstLen+1);
    endrule
    rule readData;
        let data <- axiSlave.read.readData();
        axir.readData(data, 2'b00, 0, 0);
        if (verbose) $display("        MasterSlaveConnection.readData %h", data);
    endrule
    rule writeAddr;
        Bit#(32) addr <- axiw.writeAddr;
        let burstLen = axiw.writeBurstLen;
        let burstWidth = axiw.writeBurstWidth;
        let burstType = axiw.writeBurstType;
        let burstProt = axiw.writeBurstProt;
        let burstCache = axiw.writeBurstCache;
        axiSlave.write.writeAddr(addr, burstLen, burstWidth, burstType, burstProt, burstCache);
        if (verbose) $display("        MasterSlaveConnection.writeAddr %h %d", addr, burstLen+1);
    endrule
    rule writeData;
        let data <- axiw.writeData;
        let byteEnable = axiw.writeDataByteEnable;
        let last = axiw.writeLastDataBeat;
        axiSlave.write.writeData(data, byteEnable, last);
        if (verbose) $display("        MasterSlaveConnection.writeData %h", data);
    endrule
    rule writeResponse;
        let response <- axiSlave.write.writeResponse();
        axiw.writeResponse(response, 0);
    endrule
endmodule


Fixed type error when accelerator doesn't have pins

// Copyright (c) 2016 Massachusetts Institute of Technology

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

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

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

`include "ProcConfig.bsv"

// ProcConnectal.bsv
// This is a wrapper to translate the generic Proc interface to an interface
// that is accepted by connectal.

import ConnectalConfig::*;

`ifdef CONFIG_ACCELERATOR
import Portal::*;
import AccelTop::*;
`ifdef CONFIG_STR_LEN_PINS
import StrLen::*;
`endif
`endif

// This assumes a Proc.bsv file that contains the mkProc definition
import Abstraction::*;
import BuildVector::*;
import ClientServer::*;
import Clocks::*;
import Connectable::*;
import FIFO::*;
import GetPut::*;
import Proc::*;
import Vector::*;
import VerificationPacket::*;
import MemTypes::*;
import RVTypes::*;
import SharedMemoryBridge::*;
import PerfMonitorConnectal::*;

// ProcControl
interface ProcControlRequest;
    method Action reset;
    method Action start(Bit#(64) startPc, Bit#(64) verificationPacketsToIgnore, Bool sendSynchronizationPackets);
    method Action stop;
endinterface
interface ProcControlIndication;
    method Action resetDone;
endinterface
// Platform
interface PlatformRequest;
    method Action configure(Bit#(32) ramSharedMemRefPointer, Bit#(64) ramSize, Bit#(32) romSharedMemRefPointer, Bit#(64) romSize);
    method Action memRequest(Bool write, Bit#(8) byteen, Bit#(64) addr, Bit#(64) data);
endinterface
interface PlatformIndication;
    method Action memResponse(Bool write, Bit#(64) data);
endinterface
// Verification
interface VerificationIndication;
    method Action getVerificationPacket(VerificationPacket packet);
endinterface
// PerfMonitor interfaces defined in PerfMonitor package
// ExternalMMIO
interface ExternalMMIOResponse;
    method Action response(Bool write, Bit#(64) data);
    method Action triggerExternalInterrupt;
endinterface
interface ExternalMMIORequest;
    method Action request(Bool write, Bit#(4) length, Bit#(64) addr, Bit#(64) data);
endinterface

// This is the interface of all the requests, the indications are passed in as
// parameters to the mkProcConnectal module.
interface ProcConnectal;
    interface ProcControlRequest procControlRequest;
    interface PlatformRequest platformRequest;
    interface PerfMonitorRequest perfMonitorRequest;
    interface ExternalMMIOResponse externalMMIOResponse;
    interface Vector#(1, MemReadClient#(DataBusWidth)) dmaReadClient;
    interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaWriteClient;
    interface Vector#(1, MemReadClient#(DataBusWidth)) romReadClient;
endinterface

typedef enum { Accel, Ext } ExtMemUser deriving (Bits, Eq, FShow);

module [Module] mkProcConnectal#(ProcControlIndication procControlIndication,
                                 PlatformIndication platformIndication,
                                 VerificationIndication verificationIndication,
                                 PerfMonitorIndication perfMonitorIndication,
                                 ExternalMMIORequest externalMMIORequest)
                                (ProcConnectal);
    Bool verbose = False;
    let clock <- exposeCurrentClock;
    let reset <- exposeCurrentReset;
    let procReset <- mkReset(10, True, clock);
    Reg#(Bool) resetSent <- mkReg(False);

    Proc#(MainMemoryWidth) proc <- mkProc(reset_by procReset.new_rst);

    // Address space: 0 - romSz
    SharedMemoryBridge#(MainMemoryWidth) romSharedMemoryBridge <- mkSharedMemoryBridge;
    let romToSharedMem <- mkConnection(proc.rom, romSharedMemoryBridge.to_proc);

    // Address space: 0 - ramSz
    SharedMemoryBridge#(MainMemoryWidth) ramSharedMemoryBridge <- mkSharedMemoryBridge;
    let ramToSharedMem <- mkConnection(proc.ram, ramSharedMemoryBridge.to_proc);

    FIFO#(GenericMemReq#(DataSz)) extMemReqFIFO <- mkFIFO;
    FIFO#(GenericMemResp#(DataSz)) extMemRespFIFO <- mkFIFO;
    FIFO#(ExtMemUser) extMemUserFIFO <- mkFIFO;

    rule connectExtMemReq;
        let req = extMemReqFIFO.first;
        extMemReqFIFO.deq;
        proc.extmem.request.put(req);
    endrule
    rule connectExtMemResp;
        let resp <- proc.extmem.response.get;
        extMemRespFIFO.enq(resp);
    endrule

`ifdef CONFIG_ACCELERATOR
`ifdef CONFIG_STR_LEN_PINS
    ConnectalTop#(StrLenPins) accelerator <- mkAccelTop();
`else
    ConnectalTop#(Empty) accelerator <- mkAccelTop();
`endif
    FIFO#(Bit#(1)) pendingAcceleratorReq <- mkFIFO;
    // accelerator.slave.write_server requires the writeReq to come before the
    // writeData, so writeDataFIFO holds the data until the accelerator is
    // ready for it
    FIFO#(MemData#(32)) writeDataFIFO <- mkFIFO;

    rule connectAcceleratorRequest;
        let req <- proc.mmio.request.get;
        if (req.write) begin
            if (verbose) $fdisplay(stderr, "[Accelerator Write] addr = 0x%0x, data = 0x%0x", req.addr, req.data);
            accelerator.slave.write_server.writeReq.put(
                    PhysMemRequest{
                        addr: truncate(req.addr),
                        burstLen: 4, // 4 bytes, 32-bits
                        tag: 1
                    });
            writeDataFIFO.enq(
                    MemData{
                        data: truncate(req.data),
                        tag: 1,
                        last: True
                    });
            pendingAcceleratorReq.enq(1);
        end else begin
            if (verbose) $fdisplay(stderr, "[Accelerator Read] addr = 0x%0x", req.addr);
            accelerator.slave.read_server.readReq.put(
                    PhysMemRequest{
                        addr: truncate(req.addr),
                        burstLen: 4, // 4 bytes, 32-bits
                        tag: 0
                    });
            pendingAcceleratorReq.enq(0);
        end
    endrule
    rule connectalAcceleratorWriteData;
        if (verbose) $fdisplay(stderr, "[Accelerator Write] data = 0x%0x", writeDataFIFO.first.data);
        accelerator.slave.write_server.writeData.put(writeDataFIFO.first);
        writeDataFIFO.deq;
    endrule
    rule connectAcceleratorResponse;
        Data data = 0;
        if (pendingAcceleratorReq.first == 1) begin
            if (verbose) $fdisplay(stderr, "[Accelerator Write] response");
            let tag <- accelerator.slave.write_server.writeDone.get();
        end else begin
            let readData <- accelerator.slave.read_server.readData.get();
            data = zeroExtend(readData.data);
            if (verbose) $fdisplay(stderr, "[Accelerator Read] response data = 0x%0x", data);
        end
        pendingAcceleratorReq.deq;
        proc.mmio.response.put(
                UncachedMemResp{
                    write: pendingAcceleratorReq.first == 1,
                    data: data
                });
    endrule

    // XXX: This is hard-coded for only 2 portals
    //rule connectInterrupts(accelerator.interrupt[0] || accelerator.interrupt[1]);
    //    proc.triggerExternalInterrupt;
    //endrule
    function t doRead(ReadOnly#(t) x) = x._read;
    rule connectInterrupts(fold( \|| , map(doRead, accelerator.interrupt)));
        proc.triggerExternalInterrupt;
    endrule

`ifdef CONFIG_STR_LEN_PINS
    // Only if accelerator has pins
    rule acceleratorMemReq;
        let req <- accelerator.pins.readReq;
        extMemReqFIFO.enq( GenericMemReq{
                                write: False,
                                byteen: '1,
                                addr: truncate(req),
                                data: 0
                            });
        extMemUserFIFO.enq(Accel);
    endrule
    rule acceleratorMemResp(extMemUserFIFO.first == Accel);
        let resp = extMemRespFIFO.first;
        extMemRespFIFO.deq;
        extMemUserFIFO.deq;
        accelerator.pins.readData(resp.data);
    endrule
`endif
`endif

    // rules for connecting indications
    rule finishReset(resetSent && (!procReset.isAsserted)
                               && (ramSharedMemoryBridge.numberFlyingOperations == 0)
                               && (romSharedMemoryBridge.numberFlyingOperations == 0));
        // wait for procReset to finish
        resetSent <= False;
        procControlIndication.resetDone;
    endrule
    rule connectExternalMemResponse(extMemUserFIFO.first == Ext);
        let resp = extMemRespFIFO.first;
        extMemRespFIFO.deq;
        extMemUserFIFO.deq;
        platformIndication.memResponse(resp.write, zeroExtend(resp.data));
    endrule
    rule connectVerificationIndication;
        let msg <- proc.getVerificationPacket;
        verificationIndication.getVerificationPacket(msg);
    endrule
`ifndef CONFIG_ACCELERATOR
    rule connectExternalMMIORequest;
        let msg <- proc.mmio.request.get;
        Bit#(4) length = (case (msg.size)
                B: 1;
                H: 2;
                W: 4;
                D: 8;
            endcase);
        // zero extend data in case XLEN is not 64
        externalMMIORequest.request(msg.write, length, msg.addr, zeroExtend(msg.data));
    endrule
`endif

    // request interfaces
    interface ProcControlRequest procControlRequest;
        method Action reset() if (!resetSent);
            // resets the processor
            procReset.assertReset();
            // flushes the pending memory requests
            ramSharedMemoryBridge.flushRespReqMem;
            romSharedMemoryBridge.flushRespReqMem;
            resetSent <= True;
        endmethod
        method Action start(Bit#(64) startPc, Bit#(64) verificationPacketsToIgnore, Bool sendSynchronizationPackets);
            proc.start(startPc, verificationPacketsToIgnore, sendSynchronizationPackets);
        endmethod
        method Action stop();
            proc.stop;
        endmethod
    endinterface
    interface PlatformRequest platformRequest;
        method Action configure(Bit#(32) ramSharedMemRefPointer, Bit#(64) ramSize, Bit#(32) romSharedMemRefPointer, Bit#(64) romSize);
            // configure shared memory
            ramSharedMemoryBridge.initSharedMem(ramSharedMemRefPointer, ramSize);
            // configure ROM
            romSharedMemoryBridge.initSharedMem(romSharedMemRefPointer, romSize);
        endmethod
        method Action memRequest(Bool write, Bit#(8) byteen, Bit#(64) addr, Bit#(64) data);
            extMemReqFIFO.enq( GenericMemReq{
                                    write: write,
                                    byteen: truncate(byteen),
                                    addr: truncate(addr),
                                    data: truncate(data)
                                });
            extMemUserFIFO.enq(Ext);
        endmethod
    endinterface
    interface PerfMonitorRequest perfMonitorRequest;
        method Action reset;
            noAction;
        endmethod
        method Action setEnable(Bool en);
            noAction;
        endmethod
        method Action req(Bit#(32) index);
            perfMonitorIndication.resp(0);
        endmethod
    endinterface
`ifdef CONFIG_ACCELERATOR
    // don't connect External MMIO interface
    interface ExternalMMIOResponse externalMMIOResponse;
        method Action response(Bool write, Bit#(64) data) if (False);
            noAction;
        endmethod
        method Action triggerExternalInterrupt if (False);
            noAction;
        endmethod
    endinterface
`else
    interface ExternalMMIOResponse externalMMIOResponse;
        method Action response(Bool write, Bit#(64) data);
            // truncate data in case XLEN is not 64
            proc.mmio.response.put( UncachedMemResp{write: write, data: truncate(data)} );
        endmethod
        method Action triggerExternalInterrupt;
            proc.triggerExternalInterrupt;
        endmethod
    endinterface
`endif

    // dma interfaces
    interface MemReadClient dmaReadClient = vec(ramSharedMemoryBridge.to_host_read);
    interface MemWriteClient dmaWriteClient = vec(ramSharedMemoryBridge.to_host_write);
    interface MemReadClient romReadClient = vec(romSharedMemoryBridge.to_host_read);
endmodule

// Copyright (c) 2016 Massachusetts Institute of Technology

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

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

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

`include "ProcConfig.bsv"

// ProcConnectal.bsv
// This is a wrapper to translate the generic Proc interface to an interface
// that is accepted by connectal.

import ConnectalConfig::*;

`ifdef CONFIG_ACCELERATOR
import Portal::*;
import AccelTop::*;
`ifdef CONFIG_STR_LEN_PINS
import StrLen::*;
`endif
`endif

// This assumes a Proc.bsv file that contains the mkProc definition
import Abstraction::*;
import BuildVector::*;
import ClientServer::*;
import Clocks::*;
import Connectable::*;
import FIFO::*;
import GetPut::*;
import Proc::*;
import Vector::*;
import VerificationPacket::*;
import MemTypes::*;
import RVTypes::*;
import SharedMemoryBridge::*;
import PerfMonitorConnectal::*;

// ProcControl
interface ProcControlRequest;
    method Action reset;
    method Action start(Bit#(64) startPc, Bit#(64) verificationPacketsToIgnore, Bool sendSynchronizationPackets);
    method Action stop;
endinterface
interface ProcControlIndication;
    method Action resetDone;
endinterface
// Platform
interface PlatformRequest;
    method Action configure(Bit#(32) ramSharedMemRefPointer, Bit#(64) ramSize, Bit#(32) romSharedMemRefPointer, Bit#(64) romSize);
    method Action memRequest(Bool write, Bit#(8) byteen, Bit#(64) addr, Bit#(64) data);
endinterface
interface PlatformIndication;
    method Action memResponse(Bool write, Bit#(64) data);
endinterface
// Verification
interface VerificationIndication;
    method Action getVerificationPacket(VerificationPacket packet);
endinterface
// PerfMonitor interfaces defined in PerfMonitor package
// ExternalMMIO
interface ExternalMMIOResponse;
    method Action response(Bool write, Bit#(64) data);
    method Action triggerExternalInterrupt;
endinterface
interface ExternalMMIORequest;
    method Action request(Bool write, Bit#(4) length, Bit#(64) addr, Bit#(64) data);
endinterface

// This is the interface of all the requests, the indications are passed in as
// parameters to the mkProcConnectal module.
interface ProcConnectal;
    interface ProcControlRequest procControlRequest;
    interface PlatformRequest platformRequest;
    interface PerfMonitorRequest perfMonitorRequest;
    interface ExternalMMIOResponse externalMMIOResponse;
    interface Vector#(1, MemReadClient#(DataBusWidth)) dmaReadClient;
    interface Vector#(1, MemWriteClient#(DataBusWidth)) dmaWriteClient;
    interface Vector#(1, MemReadClient#(DataBusWidth)) romReadClient;
endinterface

typedef enum { Accel, Ext } ExtMemUser deriving (Bits, Eq, FShow);

module [Module] mkProcConnectal#(ProcControlIndication procControlIndication,
                                 PlatformIndication platformIndication,
                                 VerificationIndication verificationIndication,
                                 PerfMonitorIndication perfMonitorIndication,
                                 ExternalMMIORequest externalMMIORequest)
                                (ProcConnectal);
    Bool verbose = False;
    let clock <- exposeCurrentClock;
    let reset <- exposeCurrentReset;
    let procReset <- mkReset(10, True, clock);
    Reg#(Bool) resetSent <- mkReg(False);

    Proc#(MainMemoryWidth) proc <- mkProc(reset_by procReset.new_rst);

    // Address space: 0 - romSz
    SharedMemoryBridge#(MainMemoryWidth) romSharedMemoryBridge <- mkSharedMemoryBridge;
    let romToSharedMem <- mkConnection(proc.rom, romSharedMemoryBridge.to_proc);

    // Address space: 0 - ramSz
    SharedMemoryBridge#(MainMemoryWidth) ramSharedMemoryBridge <- mkSharedMemoryBridge;
    let ramToSharedMem <- mkConnection(proc.ram, ramSharedMemoryBridge.to_proc);

    FIFO#(GenericMemReq#(DataSz)) extMemReqFIFO <- mkFIFO;
    FIFO#(GenericMemResp#(DataSz)) extMemRespFIFO <- mkFIFO;
    FIFO#(ExtMemUser) extMemUserFIFO <- mkFIFO;

    rule connectExtMemReq;
        let req = extMemReqFIFO.first;
        extMemReqFIFO.deq;
        proc.extmem.request.put(req);
    endrule
    rule connectExtMemResp;
        let resp <- proc.extmem.response.get;
        extMemRespFIFO.enq(resp);
    endrule

`ifdef CONFIG_ACCELERATOR
`ifdef CONFIG_STR_LEN_PINS
    ConnectalTop#(StrLenPins) accelerator <- mkAccelTop();
`else
    ConnectalTop#(StrLenPins) accelerator <- mkAccelTop();
`endif
    FIFO#(Bit#(1)) pendingAcceleratorReq <- mkFIFO;
    // accelerator.slave.write_server requires the writeReq to come before the
    // writeData, so writeDataFIFO holds the data until the accelerator is
    // ready for it
    FIFO#(MemData#(32)) writeDataFIFO <- mkFIFO;

    rule connectAcceleratorRequest;
        let req <- proc.mmio.request.get;
        if (req.write) begin
            if (verbose) $fdisplay(stderr, "[Accelerator Write] addr = 0x%0x, data = 0x%0x", req.addr, req.data);
            accelerator.slave.write_server.writeReq.put(
                    PhysMemRequest{
                        addr: truncate(req.addr),
                        burstLen: 4, // 4 bytes, 32-bits
                        tag: 1
                    });
            writeDataFIFO.enq(
                    MemData{
                        data: truncate(req.data),
                        tag: 1,
                        last: True
                    });
            pendingAcceleratorReq.enq(1);
        end else begin
            if (verbose) $fdisplay(stderr, "[Accelerator Read] addr = 0x%0x", req.addr);
            accelerator.slave.read_server.readReq.put(
                    PhysMemRequest{
                        addr: truncate(req.addr),
                        burstLen: 4, // 4 bytes, 32-bits
                        tag: 0
                    });
            pendingAcceleratorReq.enq(0);
        end
    endrule
    rule connectalAcceleratorWriteData;
        if (verbose) $fdisplay(stderr, "[Accelerator Write] data = 0x%0x", writeDataFIFO.first.data);
        accelerator.slave.write_server.writeData.put(writeDataFIFO.first);
        writeDataFIFO.deq;
    endrule
    rule connectAcceleratorResponse;
        Data data = 0;
        if (pendingAcceleratorReq.first == 1) begin
            if (verbose) $fdisplay(stderr, "[Accelerator Write] response");
            let tag <- accelerator.slave.write_server.writeDone.get();
        end else begin
            let readData <- accelerator.slave.read_server.readData.get();
            data = zeroExtend(readData.data);
            if (verbose) $fdisplay(stderr, "[Accelerator Read] response data = 0x%0x", data);
        end
        pendingAcceleratorReq.deq;
        proc.mmio.response.put(
                UncachedMemResp{
                    write: pendingAcceleratorReq.first == 1,
                    data: data
                });
    endrule

    // XXX: This is hard-coded for only 2 portals
    //rule connectInterrupts(accelerator.interrupt[0] || accelerator.interrupt[1]);
    //    proc.triggerExternalInterrupt;
    //endrule
    function t doRead(ReadOnly#(t) x) = x._read;
    rule connectInterrupts(fold( \|| , map(doRead, accelerator.interrupt)));
        proc.triggerExternalInterrupt;
    endrule

`ifdef CONFIG_STR_LEN_PINS
    // Only if accelerator has pins
    rule acceleratorMemReq;
        let req <- accelerator.pins.readReq;
        extMemReqFIFO.enq( GenericMemReq{
                                write: False,
                                byteen: '1,
                                addr: truncate(req),
                                data: 0
                            });
        extMemUserFIFO.enq(Accel);
    endrule
    rule acceleratorMemResp(extMemUserFIFO.first == Accel);
        let resp = extMemRespFIFO.first;
        extMemRespFIFO.deq;
        extMemUserFIFO.deq;
        accelerator.pins.readData(resp.data);
    endrule
`endif
`endif

    // rules for connecting indications
    rule finishReset(resetSent && (!procReset.isAsserted)
                               && (ramSharedMemoryBridge.numberFlyingOperations == 0)
                               && (romSharedMemoryBridge.numberFlyingOperations == 0));
        // wait for procReset to finish
        resetSent <= False;
        procControlIndication.resetDone;
    endrule
    rule connectExternalMemResponse(extMemUserFIFO.first == Ext);
        let resp = extMemRespFIFO.first;
        extMemRespFIFO.deq;
        extMemUserFIFO.deq;
        platformIndication.memResponse(resp.write, zeroExtend(resp.data));
    endrule
    rule connectVerificationIndication;
        let msg <- proc.getVerificationPacket;
        verificationIndication.getVerificationPacket(msg);
    endrule
`ifndef CONFIG_ACCELERATOR
    rule connectExternalMMIORequest;
        let msg <- proc.mmio.request.get;
        Bit#(4) length = (case (msg.size)
                B: 1;
                H: 2;
                W: 4;
                D: 8;
            endcase);
        // zero extend data in case XLEN is not 64
        externalMMIORequest.request(msg.write, length, msg.addr, zeroExtend(msg.data));
    endrule
`endif

    // request interfaces
    interface ProcControlRequest procControlRequest;
        method Action reset() if (!resetSent);
            // resets the processor
            procReset.assertReset();
            // flushes the pending memory requests
            ramSharedMemoryBridge.flushRespReqMem;
            romSharedMemoryBridge.flushRespReqMem;
            resetSent <= True;
        endmethod
        method Action start(Bit#(64) startPc, Bit#(64) verificationPacketsToIgnore, Bool sendSynchronizationPackets);
            proc.start(startPc, verificationPacketsToIgnore, sendSynchronizationPackets);
        endmethod
        method Action stop();
            proc.stop;
        endmethod
    endinterface
    interface PlatformRequest platformRequest;
        method Action configure(Bit#(32) ramSharedMemRefPointer, Bit#(64) ramSize, Bit#(32) romSharedMemRefPointer, Bit#(64) romSize);
            // configure shared memory
            ramSharedMemoryBridge.initSharedMem(ramSharedMemRefPointer, ramSize);
            // configure ROM
            romSharedMemoryBridge.initSharedMem(romSharedMemRefPointer, romSize);
        endmethod
        method Action memRequest(Bool write, Bit#(8) byteen, Bit#(64) addr, Bit#(64) data);
            extMemReqFIFO.enq( GenericMemReq{
                                    write: write,
                                    byteen: truncate(byteen),
                                    addr: truncate(addr),
                                    data: truncate(data)
                                });
            extMemUserFIFO.enq(Ext);
        endmethod
    endinterface
    interface PerfMonitorRequest perfMonitorRequest;
        method Action reset;
            noAction;
        endmethod
        method Action setEnable(Bool en);
            noAction;
        endmethod
        method Action req(Bit#(32) index);
            perfMonitorIndication.resp(0);
        endmethod
    endinterface
`ifdef CONFIG_ACCELERATOR
    // don't connect External MMIO interface
    interface ExternalMMIOResponse externalMMIOResponse;
        method Action response(Bool write, Bit#(64) data) if (False);
            noAction;
        endmethod
        method Action triggerExternalInterrupt if (False);
            noAction;
        endmethod
    endinterface
`else
    interface ExternalMMIOResponse externalMMIOResponse;
        method Action response(Bool write, Bit#(64) data);
            // truncate data in case XLEN is not 64
            proc.mmio.response.put( UncachedMemResp{write: write, data: truncate(data)} );
        endmethod
        method Action triggerExternalInterrupt;
            proc.triggerExternalInterrupt;
        endmethod
    endinterface
`endif

    // dma interfaces
    interface MemReadClient dmaReadClient = vec(ramSharedMemoryBridge.to_host_read);
    interface MemWriteClient dmaWriteClient = vec(ramSharedMemoryBridge.to_host_write);
    interface MemReadClient romReadClient = vec(romSharedMemoryBridge.to_host_read);
endmodule


AddressGenerator should increment address by DataWidthBytes

// 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 FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import RegFile::*;
import MemTypes::*;
import ConnectalConfig::*;

typedef struct {
   Bit#(addrWidth) addr;
   Bit#(BurstLenSize) bc;
   Bit#(MemTagSize) tag;
   Bool    last;
   } AddrBeat#(numeric type addrWidth) deriving (Bits);

interface AddressGenerator#(numeric type addrWidth, numeric type dataWidth);
   interface Put#(PhysMemRequest#(addrWidth,dataWidth)) request;
   interface Get#(AddrBeat#(addrWidth)) addrBeat;
endinterface

module mkAddressGenerator(AddressGenerator#(addrWidth, dataWidth))
   provisos (Div#(dataWidth,8,dataWidthBytes),
	     Log#(dataWidthBytes,beatShift));
   FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) requestFifo <- mkFIFOF1();
   FIFOF#(AddrBeat#(addrWidth)) addrBeatFifo <- mkFIFOF();
   Reg#(Bit#(addrWidth)) addrReg <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstCountReg <- mkReg(0);
   Reg#(Bool) isFirstReg <- mkReg(True);
   Reg#(Bool) isLastReg <- mkReg(False);

   rule addrBeatRule;
      let req = requestFifo.first();
      let addr = addrReg;
      let burstCount = burstCountReg;
      let isLast = isLastReg;
      if (isFirstReg) begin
	 addr = req.addr;
	 burstCount = req.burstLen >> valueOf(beatShift);
	 isLast = (req.burstLen == fromInteger(valueOf(dataWidthBytes)));
         //$display("addr=%h, burstCount=%h, isLast=%h", addr, burstCount, isLast);
      end

      let nextIsLast = burstCount == 2;
      let nextBurstCount = burstCount - 1;

      addrReg <= addr + fromInteger(valueOf(dataWidthBytes));
      burstCountReg <= nextBurstCount;
      isLastReg <= nextIsLast;
      Bool nextIsFirst = False;
      if (isLast) begin
	 requestFifo.deq();
	 nextIsFirst = True;
      end
      isFirstReg <= nextIsFirst;

      //$display("addr=%h, burstCount=%h, isLast=%h", addr, burstCount, isLast);
      addrBeatFifo.enq(AddrBeat { addr: addr, bc: burstCount, last: isLast, tag: req.tag});
   endrule

   interface Put request;
      method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
	 requestFifo.enq(req);
      endmethod
   endinterface
   interface Get addrBeat;
      method ActionValue#(AddrBeat#(addrWidth)) get();
	 addrBeatFifo.deq();
	 return addrBeatFifo.first();
      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 FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import RegFile::*;
import MemTypes::*;
import ConnectalConfig::*;

typedef struct {
   Bit#(addrWidth) addr;
   Bit#(BurstLenSize) bc;
   Bit#(MemTagSize) tag;
   Bool    last;
   } AddrBeat#(numeric type addrWidth) deriving (Bits);

interface AddressGenerator#(numeric type addrWidth, numeric type dataWidth);
   interface Put#(PhysMemRequest#(addrWidth,dataWidth)) request;
   interface Get#(AddrBeat#(addrWidth)) addrBeat;
endinterface

module mkAddressGenerator(AddressGenerator#(addrWidth, dataWidth))
   provisos (Div#(dataWidth,8,dataWidthBytes),
	     Log#(dataWidthBytes,beatShift));
   FIFOF#(PhysMemRequest#(addrWidth,dataWidth)) requestFifo <- mkFIFOF1();
   FIFOF#(AddrBeat#(addrWidth)) addrBeatFifo <- mkFIFOF();
   Reg#(Bit#(addrWidth)) addrReg <- mkReg(0);
   Reg#(Bit#(BurstLenSize)) burstCountReg <- mkReg(0);
   Reg#(Bool) isFirstReg <- mkReg(True);
   Reg#(Bool) isLastReg <- mkReg(False);

   rule addrBeatRule;
      let req = requestFifo.first();
      let addr = addrReg;
      let burstCount = burstCountReg;
      let isLast = isLastReg;
      if (isFirstReg) begin
	 addr = req.addr;
	 burstCount = req.burstLen >> valueOf(beatShift);
	 isLast = (req.burstLen == fromInteger(valueOf(dataWidthBytes)));
         //$display("addr=%h, burstCount=%h, isLast=%h", addr, burstCount, isLast);
      end

      let nextIsLast = burstCount == 2;
      let nextBurstCount = burstCount - 1;

      addrReg <= addr + 1;
      burstCountReg <= nextBurstCount;
      isLastReg <= nextIsLast;
      Bool nextIsFirst = False;
      if (isLast) begin
	 requestFifo.deq();
	 nextIsFirst = True;
      end
      isFirstReg <= nextIsFirst;

      //$display("addr=%h, burstCount=%h, isLast=%h", addr, burstCount, isLast);
      addrBeatFifo.enq(AddrBeat { addr: addr, bc: burstCount, last: isLast, tag: req.tag});
   endrule

   interface Put request;
      method Action put(PhysMemRequest#(addrWidth,dataWidth) req);
	 requestFifo.enq(req);
      endmethod
   endinterface
   interface Get addrBeat;
      method ActionValue#(AddrBeat#(addrWidth)) get();
	 addrBeatFifo.deq();
	 return addrBeatFifo.first();
      endmethod
   endinterface
endmodule


removed Probe from PcieStateChanges.bsv

removed Probe from PcieStateChanges.bsv

// Copyright (c) 2015 Connectal Project

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

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

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

import FIFOF             ::*;
import Probe             ::*;

import Pipe              ::*;

typedef enum {
   PcieCfg_none,
   PcieCfg_current_speed,
   PcieCfg_dpa_substate_change,
   PcieCfg_err_cor_out,
   PcieCfg_err_fatal_out,
   PcieCfg_err_nonfatal_out,
   PcieCfg_flr_in_process,
   PcieCfg_function_power_state,
   PcieCfg_function_status,
   PcieCfg_hot_reset_out,
   PcieCfg_link_power_state,
   PcieCfg_ltr_enable,
   PcieCfg_ltssm_state,
   PcieCfg_max_payload,
   PcieCfg_max_read_req,
   PcieCfg_negotiated_width,
   PcieCfg_obff_enable,
   PcieCfg_phy_link_down,
   PcieCfg_phy_link_status,
   PcieCfg_pl_status_change,
   PcieCfg_power_state_change_interrupt,
   PcieCfg_rcb_status,
   PcieCfg_rq_backpressure,
   PcieCfg_initial_link_width,
   PcieCfg_lane_reversal_mode,
   PcieCfg_phy_link_up,
   PcieCfg_received_hot_rst,
   PcieCfg_rx_pm_state,
   PcieCfg_sel_lnk_rate,
   PcieCfg_tx_pm_state,
   PcieCfg_link_gen2_cap,
   PcieCfg_link_partner_gen2_supported,
   PcieCfg_link_up
   } PcieCfgType deriving (Bits,Eq);

typedef struct {
   Bit#(32) timestamp;
   Bit#(8) src;
   Bit#(24) value;
} RegChange deriving (Bits);

module mkChangeSource#(Reg#(Bit#(32)) cyclesReg, Tuple2#(PcieCfgType,Bit#(24)) tpl)(PipeOut#(RegChange));
   match { .src, .v } = tpl;
   Reg#(Bit#(24))    snapshot <- mkReg(0);
   FIFOF#(RegChange) changeFifo <- mkFIFOF1();
   rule rl_update if (v != snapshot);
      if (changeFifo.notFull) begin
	 changeFifo.enq(RegChange { timestamp: cyclesReg, src: extend(pack(src)), value: extend(v) });
	 snapshot <= v;
      end
   endrule
   return toPipeOut(changeFifo);
endmodule

// Copyright (c) 2015 Connectal Project

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

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

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

import FIFOF             ::*;
import Probe             ::*;

import Pipe              ::*;

typedef enum {
   PcieCfg_none,
   PcieCfg_current_speed,
   PcieCfg_dpa_substate_change,
   PcieCfg_err_cor_out,
   PcieCfg_err_fatal_out,
   PcieCfg_err_nonfatal_out,
   PcieCfg_flr_in_process,
   PcieCfg_function_power_state,
   PcieCfg_function_status,
   PcieCfg_hot_reset_out,
   PcieCfg_link_power_state,
   PcieCfg_ltr_enable,
   PcieCfg_ltssm_state,
   PcieCfg_max_payload,
   PcieCfg_max_read_req,
   PcieCfg_negotiated_width,
   PcieCfg_obff_enable,
   PcieCfg_phy_link_down,
   PcieCfg_phy_link_status,
   PcieCfg_pl_status_change,
   PcieCfg_power_state_change_interrupt,
   PcieCfg_rcb_status,
   PcieCfg_rq_backpressure,
   PcieCfg_initial_link_width,
   PcieCfg_lane_reversal_mode,
   PcieCfg_phy_link_up,
   PcieCfg_received_hot_rst,
   PcieCfg_rx_pm_state,
   PcieCfg_sel_lnk_rate,
   PcieCfg_tx_pm_state,
   PcieCfg_link_gen2_cap,
   PcieCfg_link_partner_gen2_supported,
   PcieCfg_link_up
   } PcieCfgType deriving (Bits,Eq);

typedef struct {
   Bit#(32) timestamp;
   Bit#(8) src;
   Bit#(24) value;
} RegChange deriving (Bits);

module mkChangeSource#(Reg#(Bit#(32)) cyclesReg, Tuple2#(PcieCfgType,Bit#(24)) tpl)(PipeOut#(RegChange));
   match { .src, .v } = tpl;
   Reg#(Bit#(24))    snapshot <- mkReg(0);
   FIFOF#(RegChange) changeFifo <- mkFIFOF1();
   Probe#(Bit#(24))  probe_snapshot <- mkProbe();
   rule rl_update if (v != snapshot);
      if (changeFifo.notFull) begin
	 changeFifo.enq(RegChange { timestamp: cyclesReg, src: extend(pack(src)), value: extend(v) });
	 snapshot <= v;
	 probe_snapshot <= v;
      end
   endrule
   return toPipeOut(changeFifo);
endmodule