fixed a copy-and-edit error -- guard was False so method never ran

// 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();
	    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.
// 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


removing rule conflicts (a)

removing rule conflicts (a)

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

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

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

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

import FIFO::*;
import GetPut::*;
import Connectable::*;
import RegFile::*;

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

function Bit#(3) axiBusSize(Integer busWidth);
   if (busWidth == 32)
      return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
   else if (busWidth == 64)
      return 3'b011;
   else if (busWidth == 128)
      return 3'b100;
   else
      return 3'b011;
endfunction

typedef struct {
   Bit#(busWidth) data;
   Bit#(2) resp;
   Bit#(1) last;
   Bit#(idWidth) id;
} Axi3ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi3WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi3WriteResponse#(type idWidth) deriving (Bits);

interface Axi3Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Get#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi3Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

function Put#(t) null_put();
   return (interface Put;
	      method Action put(t x) if (False);
		 noAction;
	      endmethod
	   endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
	      method ActionValue#(t) get() if (False);
		 return ?;
	      endmethod
	   endinterface);
endfunction

function  Axi3Master#(addrWidth, busWidth, idWidth) null_axi_master();
   return (interface Axi3Master;
	      interface Get req_ar = null_get;
	      interface Put resp_read = null_put;
	      interface Get req_aw = null_get;
	      interface Get resp_write = null_get;
	      interface Put resp_b = null_put;
	   endinterface);
endfunction

interface RegFileA#(type index_t, type data_t);
   method Action upd(index_t addr, data_t d);
   method ActionValue#(data_t) sub(index_t addr);
endinterface

module mkAxi3SlaveFromRegFile#(RegFileA#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi3Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();
   let req_ar_fifo <- mkSizedFIFO(1);

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
   	 req_ar_fifo.enq(tuple3(truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8)))), req.id, req.len+1));
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get();
   	 let addr = readAddrReg;
   	 let id = readIdReg;
   	 let burstCount = readBurstCountReg;
   	 if (readBurstCountReg == 0) begin
            addr = tpl_1(req_ar_fifo.first);
   	    id = tpl_2(req_ar_fifo.first);
            burstCount = tpl_3(req_ar_fifo.first);
   	    req_ar_fifo.deq;
   	 end
         let data <- rf.sub(addr);
         if (verbose) $display("axiSlave.read.readData %h %h %d", addr, data, burstCount);
         readBurstCountReg <= burstCount - 1;
         readAddrReg <= addr + 1;
   	 readIdReg <= id;
         return Axi3ReadResponse { data: data, last: (burstCount == 1) ? 1 : 0, id: id, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

module mkAxi3SlaveOutOfRange (Axi3Slave#(addrWidth, busWidth, idWidth));

   Reg#(Bit#(addrWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(addrWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();
   let req_ar_fifo <- mkSizedFIFO(1);

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
   	 req_ar_fifo.enq(tuple3(truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8)))), req.id, req.len+1));
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get();
   	 let addr = readAddrReg;
   	 let id = readIdReg;
   	 let burstCount = readBurstCountReg;
   	 if (readBurstCountReg == 0) begin
            addr = tpl_1(req_ar_fifo.first);
   	    id = tpl_2(req_ar_fifo.first);
            burstCount = tpl_3(req_ar_fifo.first);
   	    req_ar_fifo.deq;
   	 end
         let data = 0;
         if (verbose) $display("axiSlave.read.readData %h %h %d", addr, data, burstCount);
         readBurstCountReg <= burstCount - 1;
         readAddrReg <= addr + 1;
   	 readIdReg <= id;
         return Axi3ReadResponse { data: data, last: (burstCount == 1) ? 1 : 0, id: id, resp: 2'b11 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         writeAddrReg <= req.address/fromInteger(valueOf(TDiv#(busWidth,8)));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(2'b11);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(2) resp;
    Bit#(1) last;
    Bit#(idWidth) id;
} Axi4ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi4WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi4WriteResponse#(type idWidth) deriving (Bits);

interface Axi4Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;

   interface Get#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi4Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

module mkAxi4SlaveFromRegFile#(RegFile#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi4Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi4ReadRequest#(addrWidth,idWidth) req) if (readBurstCountReg == 0);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
         readAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
	 readIdReg <= req.id;
         readBurstCountReg <= truncate(req.len)+1;
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi4ReadResponse#(busWidth,idWidth)) get() 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 Axi4ReadResponse { data: data, last: (readBurstCountReg == 1) ? 1 : 0, id: readIdReg, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi4WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= truncate(req.len)+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi4WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi4WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi4WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

instance Connectable#(Axi3Master#(addrWidth, busWidth,idWidth), Axi3Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi3Master#(addrWidth, busWidth,idWidth) m, Axi3Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance

instance Connectable#(Axi4Master#(addrWidth, busWidth,idWidth), Axi4Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi4Master#(addrWidth, busWidth,idWidth) m, Axi4Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance

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

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

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

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

import FIFO::*;
import GetPut::*;
import Connectable::*;
import RegFile::*;

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

function Bit#(3) axiBusSize(Integer busWidth);
   if (busWidth == 32)
      return 3'b010; // 3'b010: 32bit, 3'b011: 64bit, 3'b100: 128bit
   else if (busWidth == 64)
      return 3'b011;
   else if (busWidth == 128)
      return 3'b100;
   else
      return 3'b011;
endfunction

typedef struct {
   Bit#(busWidth) data;
   Bit#(2) resp;
   Bit#(1) last;
   Bit#(idWidth) id;
} Axi3ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
   Bit#(addrWidth) address;
   Bit#(4) len;
   Bit#(3) size; // assume matches bus width of Axi3Master
   Bit#(2) burst;  // drive with 2'b01
   Bit#(3) prot; // drive with 3'b000
   Bit#(4) cache; // drive with 4'b0011
   Bit#(idWidth) id;
   Bit#(2) lock;
   Bit#(4) qos;
} Axi3WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi3WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi3WriteResponse#(type idWidth) deriving (Bits);

interface Axi3Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Get#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi3Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi3ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi3ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi3WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi3WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi3WriteResponse#(idWidth)) resp_b;
endinterface

function Put#(t) null_put();
   return (interface Put;
	      method Action put(t x) if (False);
		 noAction;
	      endmethod
	   endinterface);
endfunction

function Get#(t) null_get();
   return (interface Get;
	      method ActionValue#(t) get() if (False);
		 return ?;
	      endmethod
	   endinterface);
endfunction

function  Axi3Master#(addrWidth, busWidth, idWidth) null_axi_master();
   return (interface Axi3Master;
	      interface Get req_ar = null_get;
	      interface Put resp_read = null_put;
	      interface Get req_aw = null_get;
	      interface Get resp_write = null_get;
	      interface Put resp_b = null_put;
	   endinterface);
endfunction

interface RegFileA#(type index_t, type data_t);
   method Action upd(index_t addr, data_t d);
   method ActionValue#(data_t) sub(index_t addr);
endinterface

module mkAxi3SlaveFromRegFile#(RegFileA#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi3Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req) if (readBurstCountReg == 0);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
         readAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
	 readIdReg <= req.id;
         readBurstCountReg <= req.len+1;
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get() 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 Axi3ReadResponse { data: data, last: (readBurstCountReg == 1) ? 1 : 0, id: readIdReg, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

module mkAxi3SlaveOutOfRange (Axi3Slave#(addrWidth, busWidth, idWidth));

   Reg#(Bit#(addrWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(addrWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();

   interface Put req_ar;
      method Action put(Axi3ReadRequest#(addrWidth,idWidth) req) if (readBurstCountReg == 0);
         readAddrReg <= req.address/fromInteger(valueOf(TDiv#(busWidth,8)));
	 readIdReg <= req.id;
         readBurstCountReg <= req.len+1;
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi3ReadResponse#(busWidth,idWidth)) get() if (readBurstCountReg > 0);
         let data = 0;
         readBurstCountReg <= readBurstCountReg - 1;
         readAddrReg <= readAddrReg + 1;
         return Axi3ReadResponse { data: data, last: (readBurstCountReg == 1) ? 1 : 0, id: readIdReg, resp: 2'b11 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi3WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         writeAddrReg <= req.address/fromInteger(valueOf(TDiv#(busWidth,8)));
         writeBurstCountReg <= req.len+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi3WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(2'b11);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi3WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi3WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4ReadRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(2) resp;
    Bit#(1) last;
    Bit#(idWidth) id;
} Axi4ReadResponse#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(addrWidth) address;
    Bit#(8) len;
    Bit#(3) size; // assume matches bus width of Axi4Master
    Bit#(2) burst;  // drive with 2'b01
    Bit#(3) prot; // drive with 3'b000
    Bit#(4) cache; // drive with 4'b0011
    Bit#(idWidth) id;
    Bit#(2) lock;
    Bit#(4) qos;
} Axi4WriteRequest#(type addrWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(busWidth) data;
    Bit#(TDiv#(busWidth,8)) byteEnable;
    Bit#(1)        last;
    Bit#(idWidth) id;
} Axi4WriteData#(type busWidth, type idWidth) deriving (Bits);

typedef struct {
    Bit#(2) resp;
    Bit#(idWidth) id;
} Axi4WriteResponse#(type idWidth) deriving (Bits);

interface Axi4Master#(type addrWidth, type busWidth, type idWidth);
   interface Get#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Put#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;

   interface Get#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Get#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Put#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

interface Axi4Slave#(type addrWidth, type busWidth, type idWidth);
   interface Put#(Axi4ReadRequest#(addrWidth, idWidth)) req_ar;
   interface Get#(Axi4ReadResponse#(busWidth, idWidth)) resp_read;
   interface Put#(Axi4WriteRequest#(addrWidth, idWidth)) req_aw;
   interface Put#(Axi4WriteData#(busWidth, idWidth)) resp_write;
   interface Get#(Axi4WriteResponse#(idWidth)) resp_b;
endinterface

module mkAxi4SlaveFromRegFile#(RegFile#(Bit#(regFileBusWidth), Bit#(busWidth)) rf)
   (Axi4Slave#(addrWidth, busWidth, idWidth))
   provisos(Add#(nz, regFileBusWidth, addrWidth));
   Reg#(Bit#(regFileBusWidth)) readAddrReg <- mkReg(0);
   Reg#(Bit#(regFileBusWidth)) writeAddrReg <- mkReg(0);
   Reg#(Bit#(idWidth)) readIdReg <- mkReg(0);
   Reg#(Bit#(4)) readBurstCountReg <- mkReg(0);
   Reg#(Bit#(4)) writeBurstCountReg <- mkReg(0);
   FIFO#(Bit#(2)) writeRespFifo <- mkFIFO();
   FIFO#(Bit#(idWidth)) writeIdFifo <- mkFIFO();

   Bool verbose = False;
   interface Put req_ar;
      method Action put(Axi4ReadRequest#(addrWidth,idWidth) req) if (readBurstCountReg == 0);
         if (verbose) $display("axiSlave.read.readAddr %h bc %d", req.address, req.len+1);
         readAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
	 readIdReg <= req.id;
         readBurstCountReg <= truncate(req.len)+1;
      endmethod
   endinterface: req_ar
   interface Get resp_read;
      method ActionValue#(Axi4ReadResponse#(busWidth,idWidth)) get() 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 Axi4ReadResponse { data: data, last: (readBurstCountReg == 1) ? 1 : 0, id: readIdReg, resp: 0 };
      endmethod
   endinterface: resp_read
   interface Put req_aw;
      method Action put(Axi4WriteRequest#(addrWidth,idWidth) req) if (writeBurstCountReg == 0);
         if (verbose) $display("axiSlave.write.writeAddr %h bc %d", req.address, req.len+1);
         writeAddrReg <= truncate(req.address/fromInteger(valueOf(TDiv#(busWidth,8))));
         writeBurstCountReg <= truncate(req.len)+1;
         writeIdFifo.enq(req.id);
      endmethod
   endinterface: req_aw
   interface Put resp_write;
      method Action put(Axi4WriteData#(busWidth,idWidth) resp) if (writeBurstCountReg > 0);
         if (verbose) $display("writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         rf.upd(writeAddrReg, resp.data);
         writeAddrReg <= writeAddrReg + 1;
         writeBurstCountReg <= writeBurstCountReg - 1;
         if (verbose) $display("axiSlave.write.writeData %h %h %d", writeAddrReg, resp.data, writeBurstCountReg);
         if (writeBurstCountReg == 1)
	    begin
               writeRespFifo.enq(0);
            end
      endmethod
   endinterface: resp_write
   interface Get resp_b;
      method ActionValue#(Axi4WriteResponse#(idWidth)) get();
         writeRespFifo.deq;
	 writeIdFifo.deq;
         return Axi4WriteResponse { resp: writeRespFifo.first, id: writeIdFifo.first };
      endmethod
   endinterface: resp_b
endmodule

instance Connectable#(Axi3Master#(addrWidth, busWidth,idWidth), Axi3Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi3Master#(addrWidth, busWidth,idWidth) m, Axi3Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance

instance Connectable#(Axi4Master#(addrWidth, busWidth,idWidth), Axi4Slave#(addrWidth, busWidth,idWidth));
   module mkConnection#(Axi4Master#(addrWidth, busWidth,idWidth) m, Axi4Slave#(addrWidth, busWidth,idWidth) s)(Empty);

      mkConnection(m.req_ar, s.req_ar);
      mkConnection(s.resp_read, m.resp_read);

      mkConnection(m.req_aw, s.req_aw);
      mkConnection(m.resp_write, s.resp_write);
      mkConnection(s.resp_b, m.resp_b);

   endmodule
endinstance