remove dependence on tlp.be in MemSlaveEngine

// 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 FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import MIFO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;
import Probe        :: *;

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8),
	     Add#(1, a__, busWidthWords),
	     Add#(busWidthWords, b__, 4),
	     Add#(c__, busWidthWords, 16)
      );

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFO#(TLPData#(16)) tlpWriteHeaderFifo <- mkFIFO;
    FIFO#(TLPLength)      writeDwCountFifo <- mkFIFO;
    FIFO#(Bool)             writeIs3dwFifo <- mkFIFO;
    FIFO#(Bool)             writeIsHeaderOnlyFifo <- mkFIFO;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
   MIFO#(4,busWidthWords,16,Bit#(32)) completionMimo <- mkMIFO();
   MIFO#(4,busWidthWords,16,TLPTag) completionTagMimo <- mkMIFO();

    MIMO#(busWidthWords,4,16,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    Reg#(Bit#(10)) writeBurstCount <- mkReg(0);
   FIFO#(Bit#(10)) writeBurstCountFifo <- mkFIFO();
    Reg#(TLPLength)  writeDwCount <- mkReg(0); // how many 4 byte (double) words to send
    Reg#(LUInt#(4))    tlpDwCount <- mkReg(0); // how many to send in the next tlp (at most 4)
    Reg#(Bool)            lastTlp <- mkReg(False); // if the next tlp sent is the last one
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

   Wire#(Bool) writeHeaderTlpWire <- mkDWire(False);
   Probe#(Bool) writeHeaderAvailableProbe <- mkProbe;
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);
   Probe#(Bool) writeDataMimoEnqProbe <- mkProbe;
   let    writeDataMimoCountProbe <- mkProbe;
   let writeDataMimoEnqReadyProbe <- mkProbe;
   Probe#(Bool) writeInProgressProbe <- mkProbe;
   Probe#(Bit#(10)) writeBurstCountProbe <- mkProbe;
   rule updateProbe0;
      writeDataMimoCountProbe    <= writeDataMimo.count();
      writeDataMimoEnqReadyProbe <= writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords)));
   endrule
   rule updateProbe2;
      writeHeaderAvailableProbe <= writeHeaderTlpWire;
      writeDataMimoEnqProbe <= writeDataMimoEnqWire;
   endrule

   rule writeHeaderTlp if (!writeInProgress && (!writeIs3dwFifo.first || writeDataMimo.deqReadyN(1)));
      writeHeaderTlpWire <= True;
      let tlp <- toGet(tlpWriteHeaderFifo).get();
      let dwCount <- toGet(writeDwCountFifo).get();
      let is3dw <- toGet(writeIs3dwFifo).get();
      let isHeaderOnly <- toGet(writeIsHeaderOnlyFifo).get();

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      if (is3dw) begin
	 if (hdr_3dw.format != MEM_WRITE_3DW_DATA)
	    $display("MemSlaveEngine: expecting MEM_WRITE_3DW_DATA, got %d", hdr_3dw.format);
	 Vector#(4, Bit#(32)) v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
	 tlp.be = 16'hffff;
	 if (dwCount == 1)
	    tlp.eof = True;
	 dwCount = dwCount - 1;
	 tlp.data = pack(hdr_3dw);
      end
      else begin
	 tlp.be = 16'hffff;
      end

      tlpOutFifo.enq(tlp);
      //$display("writeHeaderTlp dwCount=%d", dwCount);
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      writeInProgress <= (dwCount != 0);
      writeInProgressProbe <= (dwCount != 0);
      if (isHeaderOnly) begin
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
      end

   endrule

   rule writeTlps if (writeInProgress && writeDataMimo.deqReadyN(tlpDwCount));
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);

      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      writeDataMimo.deq(tlpDwCount);
      v = writeDataMimo.first();
      let dwCount = writeDwCount - extend(pack(tlpDwCount));
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      if (tlpDwCount == 4)
	 tlp.be = 16'hffff;
      else if (tlpDwCount == 3)
	 tlp.be = 16'hfff0;
      else if (tlpDwCount == 2)
	 tlp.be = 16'hff00;
      else if (tlpDwCount == 1)
	 tlp.be = 16'hf000;
      tlp.eof = lastTlp;
      if (lastTlp) begin
	 writeInProgress <= False;
	 writeInProgressProbe <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 //$display("writeDwCount=%d will be zero", writeDwCount);
      end

      for (Integer i = 0; i < 4; i = i + 1)
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(v[3-i]);
      tlpOutFifo.enq(tlp);
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   FIFOF#(TLPData#(16)) tlpDecodeFifo <- mkFIFOF();
   Reg#(TLPLength) wordCountReg <- mkReg(0);
   rule tlpInRule;
      let tlp <- toGet(tlpInFifo).get();
      tlpDecodeFifo.enq(tlp);
   endrule

   rule handleTlpRule;
      let tlp = tlpDecodeFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);
      let wordCount = wordCountReg;
      if (!tlp.sof) begin
	 vec = reverse(tlpvec);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReady()
	    && completionTagMimo.enqReady())
	    begin
	       UInt#(3) count = 4;
	       if (tlp.eof) begin
		  count = truncate(unpack(wordCountReg));
	       end
	       wordCount = wordCountReg - extend(pack(count));
	       completionMimo.enq(count, vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(count, tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReady()
	       && completionTagMimo.enqReady()) begin
	    vec[0] = hdr_3dw.data;
            wordCount = hdr_3dw.length - 1;
	    completionMimo.enq(1, vec);
            TLPTag tag = hdr_completion.tag;
	    lastTag <= tag;
	    completionTagMimo.enq(1, replicate(tag));
	    handled = True;
      end
      wordCountReg <= wordCount;
      //$display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled) begin
	 tlpDecodeFifo.deq();
      end
   endrule

   FIFO#(PhysMemRequest#(40)) readReqFifo <- mkFIFO();
   rule readReqRule if (!writeInProgress && !writeDataMimo.deqReady());
      let req <- toGet(readReqFifo).get();
      let burstLen = req.burstLen >> beat_shift;
      let addr = req.addr;
      let arid = req.tag;

      TLPData#(16) tlp = defaultValue;
      tlp.sof = True;
      tlp.eof = True;
      tlp.hit = 7'h00;
      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
      if (addr[39:32] != 0) begin
	 TLPMemory4DWHeader hdr_4dw = defaultValue;
	 hdr_4dw.format = MEM_READ_4DW_NO_DATA;
	 hdr_4dw.tag = extend(arid);
	 hdr_4dw.reqid = my_id;
	 hdr_4dw.nosnoop = SNOOPING_REQD;
	 hdr_4dw.addr = addr[40-1:2];
	 hdr_4dw.length = tlplen;
	 hdr_4dw.firstbe = 4'hf;
	 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_4dw);
	 tlp.be = 16'hffff;
      end
      else begin
	 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	 hdr_3dw.format = MEM_READ_3DW_NO_DATA;
	 hdr_3dw.tag = extend(arid);
	 hdr_3dw.reqid = my_id;
	 hdr_3dw.nosnoop = SNOOPING_REQD;
	 hdr_3dw.addr = addr[32-1:2];
	 hdr_3dw.length = tlplen;
	 hdr_3dw.firstbe = 4'hf;
	 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_3dw);
	 tlp.be = 16'hfff0;
      end
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface PhysMemSlave slave;
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(40) req); // if (writeBurstCount == 0);
	    let burstLen = req.burstLen >> beat_shift;
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;

	    TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
	    TLPData#(16) tlp = defaultValue;
	    tlp.sof = True;
	    tlp.eof = False;
	    tlp.hit = 7'h00;
	    tlp.be = 16'hffff;

	    $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	    if ((addr >> 32) != 0) begin
	       TLPMemory4DWHeader hdr_4dw = defaultValue;
	       hdr_4dw.format = MEM_WRITE_4DW_DATA;
	       hdr_4dw.tag = extend(awid);
	       hdr_4dw.reqid = my_id;
	       hdr_4dw.nosnoop = SNOOPING_REQD;
	       hdr_4dw.addr = addr[40-1:2];
	       hdr_4dw.length = tlplen;
	       hdr_4dw.firstbe = 4'hf;
	       hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	       tlp.data = pack(hdr_4dw);
	    end
	    else begin
	       writeIs3dw = True;
	       TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	       hdr_3dw.format = MEM_WRITE_3DW_DATA;
	       hdr_3dw.tag = extend(awid);
	       hdr_3dw.reqid = my_id;
	       hdr_3dw.nosnoop = SNOOPING_REQD;
	       hdr_3dw.addr = addr[32-1:2];
	       hdr_3dw.length = tlplen;
	       hdr_3dw.firstbe = 4'hf;
	       hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

	       tlp.be = 16'hfff0; // no data word in this TLP

	       tlp.data = pack(hdr_3dw);
	    end
	    tlpWriteHeaderFifo.enq(tlp);
	    writeDwCountFifo.enq(tlplen);
	    writeIs3dwFifo.enq(writeIs3dw);
	    writeIsHeaderOnlyFifo.enq(writeIs3dw && tlplen == 1);
	    writeBurstCountFifo.enq(extend(burstLen));
	    writeTag.enq(extend(awid));
         endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	    let burstLen = writeBurstCount;
	    if (burstLen == 0) begin
	       burstLen <- toGet(writeBurstCountFifo).get();
	    end
	    writeBurstCount <= extend(burstLen-1);
	    writeBurstCountProbe <= extend(burstLen-1);

	    Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	    writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
	    writeDataMimoEnqWire <= True;
         endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(40) req);
	    readReqFifo.enq(req);
         endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReady()
							   && completionTagMimo.deqReady());
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
	      for (Integer i = 0; i < valueOf(busWidthWords); i = i+1)
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
	      return MemData { data: v, tag: truncate(tag_v[0]), last: True};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine

// 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 FIFOF        :: *;
import GetPut       :: *;
import Connectable  :: *;
import PCIE         :: *;
import DefaultValue :: *;
import MIMO         :: *;
import MIFO         :: *;
import Vector       :: *;
import ClientServer :: *;
import MemTypes     :: *;
import Probe        :: *;

interface MemSlaveEngine#(numeric type buswidth);
    interface Client#(TLPData#(16), TLPData#(16)) tlp;
    interface PhysMemSlave#(40,buswidth) slave;
    method Bool tlpOutFifoNotEmpty();
    interface Reg#(Bool) use4dw;
endinterface: MemSlaveEngine

module mkMemSlaveEngine#(PciId my_id)(MemSlaveEngine#(buswidth))
   provisos (Div#(buswidth, 8, busWidthBytes),
	     Div#(buswidth, 32, busWidthWords),
	     Bits#(Vector#(busWidthWords, Bit#(32)), buswidth),
            Log#(busWidthBytes,beatShift),
	     Add#(aaa, 32, buswidth),
	     Add#(bbb, buswidth, 256),
	     Add#(ccc, TMul#(8, busWidthWords), 64),
	     Add#(ddd, TMul#(32, busWidthWords), 256),
	     Add#(eee, busWidthWords, 8),
	     Add#(1, a__, busWidthWords),
	     Add#(busWidthWords, b__, 4),
	     Add#(c__, busWidthWords, 16)
      );

    let beat_shift = fromInteger(valueOf(beatShift));

    FIFOF#(TLPData#(16)) tlpOutFifo <- mkFIFOF;
    FIFOF#(TLPData#(16)) tlpInFifo <- mkFIFOF;
    FIFO#(TLPData#(16)) tlpWriteHeaderFifo <- mkFIFO;
    FIFO#(TLPLength)      writeDwCountFifo <- mkFIFO;
    FIFO#(Bool)             writeIs3dwFifo <- mkFIFO;
    FIFO#(Bool)             writeIsHeaderOnlyFifo <- mkFIFO;

    Reg#(Bit#(7)) hitReg <- mkReg(0);
    Reg#(Bool) use4dwReg <- mkReg(True);

    // default configuration for MIMO is for guarded enq() and deq().
    // However, the implicit guard only checks for space for 1 element for enq(), and availability of 1 element for deq().
    MIMOConfiguration mimoCfg = defaultValue;
   MIFO#(4,busWidthWords,16,Bit#(32)) completionMimo <- mkMIFO();
   MIFO#(4,busWidthWords,16,TLPTag) completionTagMimo <- mkMIFO();

    MIMO#(busWidthWords,4,16,Bit#(32)) writeDataMimo <- mkMIMO(mimoCfg);
    Reg#(Bit#(10)) writeBurstCount <- mkReg(0);
   FIFO#(Bit#(10)) writeBurstCountFifo <- mkFIFO();
    Reg#(TLPLength)  writeDwCount <- mkReg(0); // how many 4 byte (double) words to send
    Reg#(LUInt#(4))    tlpDwCount <- mkReg(0); // how many to send in the next tlp (at most 4)
    Reg#(Bool)            lastTlp <- mkReg(False); // if the next tlp sent is the last one
    Reg#(Bool)    writeInProgress <- mkReg(False);
    FIFOF#(TLPTag) writeTag <- mkSizedFIFOF(16);
    FIFOF#(TLPTag) doneTag <- mkSizedFIFOF(16);

    function LUInt#(4) tlpWordCount(TLPData#(16) tlp);
       if (tlp.be == 16'h0000)
	  return 0;
       else if (tlp.be == 16'h000f || tlp.be == 16'hf000)
	  return 1;
       else if (tlp.be == 16'h00ff || tlp.be == 16'hff00)
	  return 2;
       else if (tlp.be == 16'h0fff || tlp.be == 16'hfff0)
	  return 3;
       else if (tlp.be == 16'hffff)
	  return 4;
       else
	  return 0;
    endfunction

   Wire#(Bool) writeHeaderTlpWire <- mkDWire(False);
   Probe#(Bool) writeHeaderAvailableProbe <- mkProbe;
   Wire#(Bool) writeDataMimoEnqWire <- mkDWire(False);
   Probe#(Bool) writeDataMimoEnqProbe <- mkProbe;
   let    writeDataMimoCountProbe <- mkProbe;
   let writeDataMimoEnqReadyProbe <- mkProbe;
   Probe#(Bool) writeInProgressProbe <- mkProbe;
   Probe#(Bit#(10)) writeBurstCountProbe <- mkProbe;
   rule updateProbe0;
      writeDataMimoCountProbe    <= writeDataMimo.count();
      writeDataMimoEnqReadyProbe <= writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords)));
   endrule
   rule updateProbe2;
      writeHeaderAvailableProbe <= writeHeaderTlpWire;
      writeDataMimoEnqProbe <= writeDataMimoEnqWire;
   endrule

   rule writeHeaderTlp if (!writeInProgress && (!writeIs3dwFifo.first || writeDataMimo.deqReadyN(1)));
      writeHeaderTlpWire <= True;
      let tlp <- toGet(tlpWriteHeaderFifo).get();
      let dwCount <- toGet(writeDwCountFifo).get();
      let is3dw <- toGet(writeIs3dwFifo).get();
      let isHeaderOnly <- toGet(writeIsHeaderOnlyFifo).get();

      TLPMemory4DWHeader hdr_4dw = unpack(tlp.data);

      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      if (is3dw) begin
	 if (hdr_3dw.format != MEM_WRITE_3DW_DATA)
	    $display("MemSlaveEngine: expecting MEM_WRITE_3DW_DATA, got %d", hdr_3dw.format);
	 Vector#(4, Bit#(32)) v = writeDataMimo.first();
	 writeDataMimo.deq(1);
	 hdr_3dw.data = byteSwap(v[0]);
	 tlp.be = 16'hffff;
	 if (dwCount == 1)
	    tlp.eof = True;
	 dwCount = dwCount - 1;
	 tlp.data = pack(hdr_3dw);
      end
      else begin
	 tlp.be = 16'hffff;
      end

      tlpOutFifo.enq(tlp);
      //$display("writeHeaderTlp dwCount=%d", dwCount);
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      writeInProgress <= (dwCount != 0);
      writeInProgressProbe <= (dwCount != 0);
      if (isHeaderOnly) begin
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
      end

   endrule

   rule writeTlps if (writeInProgress && writeDataMimo.deqReadyN(tlpDwCount));
      TLPData#(16) tlp = defaultValue;
      tlp.sof = False;
      Vector#(4, Bit#(32)) v = unpack(0);

      // The MIMO implicit guard only checks for availability of 1 element
      // so we explicitly check for the number of elements required
      writeDataMimo.deq(tlpDwCount);
      v = writeDataMimo.first();
      let dwCount = writeDwCount - extend(pack(tlpDwCount));
      writeDwCount <= dwCount;
      tlpDwCount <= truncate(min(4,unpack(dwCount)));
      lastTlp <= (dwCount <= 4);
      if (tlpDwCount == 4)
	 tlp.be = 16'hffff;
      else if (tlpDwCount == 3)
	 tlp.be = 16'hfff0;
      else if (tlpDwCount == 2)
	 tlp.be = 16'hff00;
      else if (tlpDwCount == 1)
	 tlp.be = 16'hf000;
      tlp.eof = lastTlp;
      if (lastTlp) begin
	 writeInProgress <= False;
	 writeInProgressProbe <= False;
	 doneTag.enq(writeTag.first());
	 writeTag.deq();
	 //$display("writeDwCount=%d will be zero", writeDwCount);
      end

      for (Integer i = 0; i < 4; i = i + 1)
	 tlp.data[(i+1)*32-1:i*32] = byteSwap(v[3-i]);
      tlpOutFifo.enq(tlp);
   endrule

   Reg#(TLPTag) lastTag <- mkReg(0);
   FIFOF#(TLPData#(16)) tlpDecodeFifo <- mkFIFOF();
   FIFOF#(LUInt#(4))    tlpWordCountFifo <- mkFIFOF();
   rule tlpInRule;
      let tlp <- toGet(tlpInFifo).get();
      tlpWordCountFifo.enq(tlpWordCount(tlp));
      tlpDecodeFifo.enq(tlp);
   endrule

   rule handleTlpRule;
      let tlp = tlpDecodeFifo.first;
      let count = tlpWordCountFifo.first;
      Bool handled = False;
      TLPMemoryIO3DWHeader h = unpack(tlp.data);
      hitReg <= tlp.hit;
      TLPMemoryIO3DWHeader hdr_3dw = unpack(tlp.data);
      TLPCompletionHeader hdr_completion = unpack(tlp.data);
      Vector#(4, Bit#(32)) vec = unpack(0);
      Vector#(4, Bit#(32)) tlpvec = unpack(tlp.data);

      if (!tlp.sof) begin
	 vec = reverse(tlpvec);
	 // The MIMO implicit guard only checks for space to enqueue 1 element
	 // so we explicitly check for the number of elements required
	 // otherwise elements in the queue will be overwritten.
	 if (completionMimo.enqReady()
	    && completionTagMimo.enqReady())
	    begin
	       completionMimo.enq(count, vec);
	       Vector#(4, TLPTag) tagvec = replicate(lastTag);
	       completionTagMimo.enq(count, tagvec);
	       handled = True;
	    end
      end
      else if (hdr_3dw.format == MEM_WRITE_3DW_DATA
	       && hdr_3dw.pkttype == COMPLETION
	       && completionMimo.enqReady()
	       && completionTagMimo.enqReady()) begin
	    vec[0] = hdr_3dw.data;
	    completionMimo.enq(1, vec);
            TLPTag tag = hdr_completion.tag;
	    lastTag <= tag;
	    completionTagMimo.enq(1, replicate(tag));
	    handled = True;
      end
      //$display("tlpIn handled=%d tlp=%h\n", handled, tlp);
      if (handled) begin
	 tlpDecodeFifo.deq();
	 tlpWordCountFifo.deq();
      end
   endrule

   FIFO#(PhysMemRequest#(40)) readReqFifo <- mkFIFO();
   rule readReqRule if (!writeInProgress && !writeDataMimo.deqReady());
      let req <- toGet(readReqFifo).get();
      let burstLen = req.burstLen >> beat_shift;
      let addr = req.addr;
      let arid = req.tag;

      TLPData#(16) tlp = defaultValue;
      tlp.sof = True;
      tlp.eof = True;
      tlp.hit = 7'h00;
      TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
      if (addr[39:32] != 0) begin
	 TLPMemory4DWHeader hdr_4dw = defaultValue;
	 hdr_4dw.format = MEM_READ_4DW_NO_DATA;
	 hdr_4dw.tag = extend(arid);
	 hdr_4dw.reqid = my_id;
	 hdr_4dw.nosnoop = SNOOPING_REQD;
	 hdr_4dw.addr = addr[40-1:2];
	 hdr_4dw.length = tlplen;
	 hdr_4dw.firstbe = 4'hf;
	 hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_4dw);
	 tlp.be = 16'hffff;
      end
      else begin
	 TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	 hdr_3dw.format = MEM_READ_3DW_NO_DATA;
	 hdr_3dw.tag = extend(arid);
	 hdr_3dw.reqid = my_id;
	 hdr_3dw.nosnoop = SNOOPING_REQD;
	 hdr_3dw.addr = addr[32-1:2];
	 hdr_3dw.length = tlplen;
	 hdr_3dw.firstbe = 4'hf;
	 hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	 tlp.data = pack(hdr_3dw);
	 tlp.be = 16'hfff0;
      end
      tlpOutFifo.enq(tlp);
   endrule

    interface Client        tlp;
        interface request = toGet(tlpOutFifo);
        interface response = toPut(tlpInFifo);
    endinterface
    interface PhysMemSlave slave;
   interface PhysMemWriteServer write_server;
      interface Put writeReq;
         method Action put(PhysMemRequest#(40) req); // if (writeBurstCount == 0);
	    let burstLen = req.burstLen >> beat_shift;
	    let addr = req.addr;
	    let awid = req.tag;
	    let writeIs3dw = False;

	    TLPLength tlplen = fromInteger(valueOf(busWidthWords))*extend(burstLen);
	    TLPData#(16) tlp = defaultValue;
	    tlp.sof = True;
	    tlp.eof = False;
	    tlp.hit = 7'h00;
	    tlp.be = 16'hffff;

	    $display("slave.writeAddr tlplen=%d burstLen=%d", tlplen, burstLen);
	    if ((addr >> 32) != 0) begin
	       TLPMemory4DWHeader hdr_4dw = defaultValue;
	       hdr_4dw.format = MEM_WRITE_4DW_DATA;
	       hdr_4dw.tag = extend(awid);
	       hdr_4dw.reqid = my_id;
	       hdr_4dw.nosnoop = SNOOPING_REQD;
	       hdr_4dw.addr = addr[40-1:2];
	       hdr_4dw.length = tlplen;
	       hdr_4dw.firstbe = 4'hf;
	       hdr_4dw.lastbe = (tlplen > 1) ? 4'hf : 0;
	       tlp.data = pack(hdr_4dw);
	    end
	    else begin
	       writeIs3dw = True;
	       TLPMemoryIO3DWHeader hdr_3dw = defaultValue;
	       hdr_3dw.format = MEM_WRITE_3DW_DATA;
	       hdr_3dw.tag = extend(awid);
	       hdr_3dw.reqid = my_id;
	       hdr_3dw.nosnoop = SNOOPING_REQD;
	       hdr_3dw.addr = addr[32-1:2];
	       hdr_3dw.length = tlplen;
	       hdr_3dw.firstbe = 4'hf;
	       hdr_3dw.lastbe = (tlplen > 1) ? 4'hf : 0;

	       tlp.be = 16'hfff0; // no data word in this TLP

	       tlp.data = pack(hdr_3dw);
	    end
	    tlpWriteHeaderFifo.enq(tlp);
	    writeDwCountFifo.enq(tlplen);
	    writeIs3dwFifo.enq(writeIs3dw);
	    writeIsHeaderOnlyFifo.enq(writeIs3dw && tlplen == 1);
	    writeBurstCountFifo.enq(extend(burstLen));
	    writeTag.enq(extend(awid));
         endmethod
	endinterface
      interface Put writeData;
         method Action put(MemData#(buswidth) wdata)
	      provisos (Bits#(Vector#(busWidthWords, Bit#(32)), busWidth)) if (writeDataMimo.enqReadyN(fromInteger(valueOf(busWidthWords))));

	    let burstLen = writeBurstCount;
	    if (burstLen == 0) begin
	       burstLen <- toGet(writeBurstCountFifo).get();
	    end
	    writeBurstCount <= extend(burstLen-1);
	    writeBurstCountProbe <= extend(burstLen-1);

	    Vector#(busWidthWords, Bit#(32)) v = unpack(wdata.data);
	    writeDataMimo.enq(fromInteger(valueOf(busWidthWords)), v);
	    writeDataMimoEnqWire <= True;
         endmethod
       endinterface
      interface Get writeDone;
         method ActionValue#(Bit#(MemTagSize)) get();
	      let tag = doneTag.first();
	      doneTag.deq();
	      return truncate(tag);
           endmethod
	endinterface
   endinterface
   interface PhysMemReadServer read_server;
      interface Put readReq;
         method Action put(PhysMemRequest#(40) req);
	    readReqFifo.enq(req);
         endmethod
       endinterface
      interface Get     readData;
         method ActionValue#(MemData#(buswidth)) get() if (completionMimo.deqReady()
							   && completionTagMimo.deqReady());
	      let data_v = completionMimo.first;
	      let tag_v = completionTagMimo.first;
	      completionMimo.deq();
	      completionTagMimo.deq();
              Bit#(buswidth) v = 0;
	      for (Integer i = 0; i < valueOf(busWidthWords); i = i+1)
		 v[(i+1)*32-1:i*32] = byteSwap(data_v[i]);
	      return MemData { data: v, tag: truncate(tag_v[0]), last: True};
           endmethod
	endinterface
   endinterface
    endinterface: slave
   method Bool tlpOutFifoNotEmpty() = tlpOutFifo.notEmpty;
   interface Reg use4dw = use4dwReg;
endmodule: mkMemSlaveEngine


eliminate two unnecessary FIFOs in mkMemWriteEngineBuff

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Vector::*;
import BuildVector::*;
import Cntrs::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import MemTypes::*;
import Pipe::*;
import ConnectalConfig::*;

`include "ConnectalProjectConfig.bsv"

module mkMemWriteEngine(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Add#(1, d__, busWidth)
	    ,Add#(1, d__, userWidth)
	    ,Add#(e__, TLog#(numServers), MemTagSize)
	    ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
	    ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
	    ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	    );
   let rv <- mkMemWriteEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

interface MemWriteChannel#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth);
   interface PipeIn#(Bit#(MemTagSize))        writeGnt; // grants request
   interface PipeOut#(MemRequest)             writeReq;
   interface PipeOut#(MemData#(userWidth))    writeData;
   interface PipeIn#(Bit#(MemTagSize))        writeDone;
   interface MemWriteEngineServer#(userWidth) writeServer;
endinterface

module mkMemWriteChannel#(Integer bufferSizeBytes, Integer channelNumber,
			  PipeOut#(Bit#(MemTagSize)) writeGntPipe, PipeOut#(Bit#(MemTagSize)) writeDonePipe)
   (MemWriteChannel#(busWidth, userWidth, cmdQDepth))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, d__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))       serverCond <- mkFIFO1();
   FIFO#(Tuple2#(Bit#(MemTagSize),MemengineCmd)) serverReq <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(MemTagSize),Bool))inProgress <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(MemTagSize),Bit#(MemTagSize),Bool)) serverDone <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFOF#(MemRequest)           writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();

   Reg#(Bool)              clientInFlight <- mkReg(False);
   Reg#(Bool)              clientBursts <- mkReg(False);
   ConfigCounter#(16)      clientAvail <- mkConfigCounter(0);
   Reg#(MemengineCmd)      clientStart <- mkReg(unpack(0));
   FIFO#(Bool)             clientFinished <- mkSizedFIFO(1);
   FIFOF#(MemengineCmd)    clientCommand <- mkSizedFIFOF(1);
   Count#(Bit#(32))        clientCycles     <- mkCount(0);
   FIFOF#(MemRequestCycles) clientCyclesFifo <- mkFIFOF();
   FIFOF#(Bit#(userWidth)) dataBuffer <- mkSizedBRAMFIFOF(bufferSizeBeats);
   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule rl_cycles;
      cycles <= cycles + 1;
   endrule

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   rule store_cmd if (!clientInFlight);
      let cmd <- toGet(clientCommand).get();
      clientInFlight <= True;
      clientBursts <= True;
      clientStart <= cmd;
      $display("cycles %d starting request %d bytes %d", cycles, cmd.tag, cmd.len);
      clientCycles <= 0;
   endrule
   rule rule_request_cycles;
      clientCycles.incr(1);
   endrule

   rule load_ctxt_a if (!load_in_progress);
      if (clientBursts) begin
	 load_in_progress <= True;
	 let cmd = clientStart;
	 let cond0 <- clientAvail.maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 serverCond.enq(tuple3(cmd,cond0,cond1));
      end
   endrule

   rule load_ctxt_b if (load_in_progress);
      load_in_progress <= False;
      match {.cmd,.cond0,.cond1} <- toGet(serverCond).get;
      if  (cond0) begin
	 //$display("load_ctxt_b cycles %d %h", cycles, cmd.base);
	 serverReq.enq(tuple2(0,cmd));
	 if (cond1) begin
	    clientBursts <= False;
	 end
	 else begin
	    clientStart <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
               burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule rlWriteReq;
      match {.idx, .cmd} <- toGet(serverReq).get;
      Bit#(BurstLenSize) bl = cmd.burstLen;
      Bool last = False;
      if (cmd.len <= extend(bl)) begin
	 last = True;
	 bl = truncate(cmd.len);
      end
      inProgress.enq(tuple3(truncate(bl>>beat_shift), cmd.tag, last));
      //$display("writeReq %d, %h %h %h", channelNumber, cmd.base, bl, last);
      writeReqFifo.enq(MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: fromInteger(channelNumber)});
   endrule

   rule rlWriteData;
      match {.rc, .client_tag, .last} = inProgress.first;
      let gnt = writeGntPipe.first;
      let new_respCnt = respCnt+1;
      let lastBeat = False;
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 inProgress.deq();
	 writeGntPipe.deq();
	 serverDone.enq(tuple3(0,client_tag,last));
	 lastBeat = True;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      let wd <- toGet(dataBuffer).get();
      writeDataFifo.enq(MemData{data:wd, tag:fromInteger(channelNumber), last:lastBeat});
   endrule

   rule rlWriteDone;
      let tag <- toGet(writeDonePipe).get();
      match {.idx, .req_tag, .last} <- toGet(serverDone).get;
      if (last) begin
	 clientInFlight <= False;
	 clientFinished.enq(True);
`ifdef MEMENGINE_REQUEST_CYCLES
	 $display("cycles %d req_tag %d clientCycles = %d", cycles, req_tag, clientCycles);
	 clientCyclesFifo.enq(MemRequestCycles { tag: req_tag, cycles: clientCycles });
`endif
      end
      //$display("writeDone %d %d", channelNumber, last);
   endrule

   MemWriteEngineServer#(userWidth) ws = (interface MemWriteEngineServer#(userWidth);
      interface Put request;
	 method Action put(MemengineCmd cmd);
	    Bit#(32) bsb = fromInteger(bufferSizeBytes);
      `ifdef SIMULATION
	    Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
	    Bit#(32) bl = extend(cmd.burstLen);
	    // this is because bsc lifts the divide operation (below)
	    // and on startup the simulator gets a floating-point exception
	    if (bl ==0)
	       bl = 1;
	    let mdw0 = ((cmd.len)/bl)*bl != cmd.len;
	    let mdw1 = ((cmd.len)/dw)*dw != cmd.len;
	    let bbl = extend(cmd.burstLen) > bsb;
	    if(bbl || mdw0 || mdw1 || cmd.len == 0) begin
	       if (bbl)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
	       if (mdw0 || mdw1 || cmd.len == 0)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported len %h mdw0=%d mdw1=%d", cmd.len, mdw0, mdw1);
	    end
	    else
      `endif
	       begin
		  clientCommand.enq(cmd);
		  $display("(%d) %h %h %h", channelNumber, cmd.base, cmd.len, cmd.burstLen);
	       end
	 endmethod
      endinterface
      interface Get done;
	 method ActionValue#(Bool) get = toGet(clientFinished).get;
      endinterface
      interface PipeIn data = interface PipeIn;
				 method Bool notFull = dataBuffer.notFull;
   				 method Action enq(Bit#(userWidth) v);
				    dataBuffer.enq(v);
				    clientAvail.increment(1);
				 endmethod
			      endinterface;
	 interface PipeOut requestCycles = toPipeOut(clientCyclesFifo);
	 endinterface);
   interface writeServer = ws;
   interface writeReq = toPipeOut(writeReqFifo);
   interface writeData = toPipeOut(writeDataFifo);
endmodule

module mkMemWriteEngineBuff#(Integer bufferSizeBytes)(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, a__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     ,Add#(b__, TLog#(numServers), MemTagSize)
             ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
             ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
             ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	     );

   FIFOF#(Bit#(MemTagSize)) writeDoneFifo <- mkFIFOF();
   FIFOF#(Bit#(MemTagSize))       arbFifo <- mkFIFOF1();
   function Tuple2#(Bit#(TLog#(numServers)),Bit#(MemTagSize)) tagDone(Bit#(MemTagSize) tag);
      return tuple2(truncate(tag), tag);
   endfunction
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) arbPipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(arbFifo))));
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) donePipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(writeDoneFifo))));
   Vector#(numServers, MemWriteChannel#(busWidth,userWidth,cmdQDepth)) writeChannels <- zipWith3M(mkMemWriteChannel(bufferSizeBytes),
												  genVector(),
												  arbPipes,
												  donePipes);
   function PipeOut#(MemRequest) writeChannelDmaWriteReq(Integer i);
      return writeChannels[i].writeReq;
   endfunction
   function PipeOut#(MemData#(userWidth)) writeChannelDmaWriteData(Integer i);
      return writeChannels[i].writeData;
   endfunction
   function MemWriteEngineServer#(userWidth) writeChannelServer(Integer i);
      return writeChannels[i].writeServer;
   endfunction

   Reg#(Bool)         reqInFlight <- mkReg(False);
   FIFOF#(MemRequest)          writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();
   FunnelPipe#(1,numServers,MemRequest,2) reqFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteReq));
   FunnelPipe#(1,numServers,MemData#(userWidth),2) dataFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteData));

   rule rl_arbitration if (!reqInFlight);
      let req <- toGet(reqFunnel[0]).get();
      // tag is channel number
      arbFifo.enq(req.tag);
      writeReqFifo.enq(req);
      reqInFlight <= True;
   endrule
   rule rl_writeData if (reqInFlight);
      MemData#(userWidth) md <- toGet(dataFunnel[0]).get();
      if (md.last)
	 reqInFlight <= False;
      writeDataFifo.enq(md);
   endrule

   interface writeServers = genWith(writeChannelServer);
   interface MemWriteClient dmaClient;
      interface writeReq = toGet(writeReqFifo);
      interface writeData = toGet(writeDataFifo);
      interface writeDone = toPut(writeDoneFifo);
   endinterface: dmaClient

endmodule

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

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

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

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Vector::*;
import BuildVector::*;
import Cntrs::*;
import FIFOF::*;
import FIFO::*;
import GetPut::*;
import Connectable::*;
import BRAMFIFO::*;
import ConfigCounter::*;
import MemTypes::*;
import Pipe::*;
import ConnectalConfig::*;

`include "ConnectalProjectConfig.bsv"

module mkMemWriteEngine(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos( Add#(1, d__, busWidth)
	    ,Add#(1, d__, userWidth)
	    ,Add#(e__, TLog#(numServers), MemTagSize)
	    ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
	    ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
	    ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	    );
   let rv <- mkMemWriteEngineBuff(valueOf(TExp#(BurstLenSize)));
   return rv;
endmodule

interface MemWriteChannel#(numeric type busWidth, numeric type userWidth, numeric type cmdQDepth);
   interface PipeIn#(Bit#(MemTagSize))        writeGnt; // grants request
   interface PipeOut#(MemRequest)             writeReq;
   interface PipeOut#(MemData#(userWidth))    writeData;
   interface PipeIn#(Bit#(MemTagSize))        writeDone;
   interface MemWriteEngineServer#(userWidth) writeServer;
endinterface

module mkMemWriteChannel#(Integer bufferSizeBytes, Integer channelNumber)(MemWriteChannel#(busWidth, userWidth, cmdQDepth))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, d__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     );

   Integer bufferSizeBeats = bufferSizeBytes/valueOf(busWidthBytes);
   Reg#(Bool) load_in_progress <- mkReg(False);
   FIFO#(Tuple3#(MemengineCmd,Bool,Bool))       serverCond <- mkFIFO1();
   FIFO#(Tuple2#(Bit#(MemTagSize),MemengineCmd)) serverReq <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(8),Bit#(MemTagSize),Bool))inProgress <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFO#(Tuple3#(Bit#(MemTagSize),Bit#(MemTagSize),Bool)) serverDone <- mkSizedFIFO(valueOf(cmdQDepth));
   FIFOF#(MemRequest)           writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();
   FIFOF#(Bit#(MemTagSize))    writeDoneFifo <- mkFIFOF();
   FIFOF#(Bit#(MemTagSize))     writeGntFifo <- mkFIFOF();

   Reg#(Bool)              clientInFlight <- mkReg(False);
   Reg#(Bool)              clientBursts <- mkReg(False);
   ConfigCounter#(16)      clientAvail <- mkConfigCounter(0);
   Reg#(MemengineCmd)      clientStart <- mkReg(unpack(0));
   FIFO#(Bool)             clientFinished <- mkSizedFIFO(1);
   FIFOF#(MemengineCmd)    clientCommand <- mkSizedFIFOF(1);
   Count#(Bit#(32))        clientCycles     <- mkCount(0);
   FIFOF#(MemRequestCycles) clientCyclesFifo <- mkFIFOF();
   FIFOF#(Bit#(userWidth)) dataBuffer <- mkSizedBRAMFIFOF(bufferSizeBeats);
   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule rl_cycles;
      cycles <= cycles + 1;
   endrule

   Reg#(Bit#(8))                    respCnt <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   rule store_cmd if (!clientInFlight);
      let cmd <- toGet(clientCommand).get();
      clientInFlight <= True;
      clientBursts <= True;
      clientStart <= cmd;
      $display("cycles %d starting request %d bytes %d", cycles, cmd.tag, cmd.len);
      clientCycles <= 0;
   endrule
   rule rule_request_cycles;
      clientCycles.incr(1);
   endrule

   rule load_ctxt_a if (!load_in_progress);
      if (clientBursts) begin
	 load_in_progress <= True;
	 let cmd = clientStart;
	 let cond0 <- clientAvail.maybeDecrement(unpack(extend(cmd.burstLen>>beat_shift)));
	 let cond1 = cmd.len <= extend(cmd.burstLen);
	 serverCond.enq(tuple3(cmd,cond0,cond1));
      end
   endrule

   rule load_ctxt_b if (load_in_progress);
      load_in_progress <= False;
      match {.cmd,.cond0,.cond1} <- toGet(serverCond).get;
      if  (cond0) begin
	 //$display("load_ctxt_b cycles %d %h", cycles, cmd.base);
	 serverReq.enq(tuple2(0,cmd));
	 if (cond1) begin
	    clientBursts <= False;
	 end
	 else begin
	    clientStart <= MemengineCmd{sglId:cmd.sglId, base:cmd.base+extend(cmd.burstLen),
               burstLen:cmd.burstLen, len:cmd.len-extend(cmd.burstLen), tag:cmd.tag};
	 end
      end
   endrule

   rule rlWriteReq;
      match {.idx, .cmd} <- toGet(serverReq).get;
      Bit#(BurstLenSize) bl = cmd.burstLen;
      Bool last = False;
      if (cmd.len <= extend(bl)) begin
	 last = True;
	 bl = truncate(cmd.len);
      end
      inProgress.enq(tuple3(truncate(bl>>beat_shift), cmd.tag, last));
      //$display("writeReq %d, %h %h %h", channelNumber, cmd.base, bl, last);
      writeReqFifo.enq(MemRequest { sglId: cmd.sglId, offset: extend(cmd.base), burstLen:bl, tag: fromInteger(channelNumber)});
   endrule

   rule rlWriteData;
      match {.rc, .client_tag, .last} = inProgress.first;
      let gnt = writeGntFifo.first;
      let new_respCnt = respCnt+1;
      let lastBeat = False;
      if (new_respCnt == rc) begin
	 respCnt <= 0;
	 inProgress.deq();
	 writeGntFifo.deq();
	 serverDone.enq(tuple3(0,client_tag,last));
	 lastBeat = True;
      end
      else begin
	 respCnt <= new_respCnt;
      end
      let wd <- toGet(dataBuffer).get();
      writeDataFifo.enq(MemData{data:wd, tag:fromInteger(channelNumber), last:lastBeat});
   endrule

   rule rlWriteDone;
      let tag <- toGet(writeDoneFifo).get();
      match {.idx, .req_tag, .last} <- toGet(serverDone).get;
      if (last) begin
	 clientInFlight <= False;
	 clientFinished.enq(True);
`ifdef MEMENGINE_REQUEST_CYCLES
	 $display("cycles %d req_tag %d clientCycles = %d", cycles, req_tag, clientCycles);
	 clientCyclesFifo.enq(MemRequestCycles { tag: req_tag, cycles: clientCycles });
`endif
      end
      //$display("writeDone %d %d", channelNumber, last);
   endrule

   MemWriteEngineServer#(userWidth) ws = (interface MemWriteEngineServer#(userWidth);
      interface Put request;
	 method Action put(MemengineCmd cmd);
	    Bit#(32) bsb = fromInteger(bufferSizeBytes);
      `ifdef SIMULATION
	    Bit#(32) dw = fromInteger(valueOf(busWidthBytes));
	    Bit#(32) bl = extend(cmd.burstLen);
	    // this is because bsc lifts the divide operation (below)
	    // and on startup the simulator gets a floating-point exception
	    if (bl ==0)
	       bl = 1;
	    let mdw0 = ((cmd.len)/bl)*bl != cmd.len;
	    let mdw1 = ((cmd.len)/dw)*dw != cmd.len;
	    let bbl = extend(cmd.burstLen) > bsb;
	    if(bbl || mdw0 || mdw1 || cmd.len == 0) begin
	       if (bbl)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported burstLen %d %d", bsb, cmd.burstLen);
	       if (mdw0 || mdw1 || cmd.len == 0)
					  $display("XXXXXXXXXX mkMemWriteEngineBuff::unsupported len %h mdw0=%d mdw1=%d", cmd.len, mdw0, mdw1);
	    end
	    else
      `endif
	       begin
		  clientCommand.enq(cmd);
		  $display("(%d) %h %h %h", channelNumber, cmd.base, cmd.len, cmd.burstLen);
	       end
	 endmethod
      endinterface
      interface Get done;
	 method ActionValue#(Bool) get = toGet(clientFinished).get;
      endinterface
      interface PipeIn data = interface PipeIn;
				 method Bool notFull = dataBuffer.notFull;
   				 method Action enq(Bit#(userWidth) v);
				    dataBuffer.enq(v);
				    clientAvail.increment(1);
				 endmethod
			      endinterface;
	 interface PipeOut requestCycles = toPipeOut(clientCyclesFifo);
	 endinterface);
   interface writeServer = ws;
   interface writeGnt = toPipeIn(writeGntFifo);
   interface writeReq = toPipeOut(writeReqFifo);
   interface writeData = toPipeOut(writeDataFifo);
   interface writeDone = toPipeIn(writeDoneFifo);
endmodule

module mkMemWriteEngineBuff#(Integer bufferSizeBytes)(MemWriteEngine#(busWidth, userWidth, cmdQDepth, numServers))
   provisos ( Div#(busWidth,8,busWidthBytes)
	     ,Log#(busWidthBytes,beatShift)
	     ,Add#(1, a__, userWidth)
	     ,Add#(userWidth, 0, busWidth)
	     ,Add#(b__, TLog#(numServers), MemTagSize)
             ,FunnelPipesPipelined#(1, numServers, MemData#(userWidth), 2)
             ,FunnelPipesPipelined#(1, numServers, MemRequest, 2)
             ,FunnelPipesPipelined#(1, numServers, Bit#(MemTagSize), 2)
	     );
   Vector#(numServers, MemWriteChannel#(busWidth,userWidth,cmdQDepth)) writeChannels <- genWithM(mkMemWriteChannel(bufferSizeBytes));
   function PipeOut#(MemRequest) writeChannelDmaWriteReq(Integer i);
      return writeChannels[i].writeReq;
   endfunction
   function PipeOut#(MemData#(userWidth)) writeChannelDmaWriteData(Integer i);
      return writeChannels[i].writeData;
   endfunction
   function MemWriteEngineServer#(userWidth) writeChannelServer(Integer i);
      return writeChannels[i].writeServer;
   endfunction

   Reg#(Bool)         reqInFlight <- mkReg(False);
   FIFOF#(MemRequest)          writeReqFifo <- mkFIFOF();
   FIFOF#(MemData#(userWidth)) writeDataFifo <- mkFIFOF();
   FIFOF#(Bit#(MemTagSize))    writeDoneFifo <- mkFIFOF();

   FIFOF#(Bit#(MemTagSize)) arbFifo <- mkFIFOF1();
   FunnelPipe#(1,numServers,MemRequest,2) reqFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteReq));
   FunnelPipe#(1,numServers,MemData#(userWidth),2) dataFunnel <- mkFunnelPipesPipelined(genWith(writeChannelDmaWriteData));
   function Tuple2#(Bit#(TLog#(numServers)),Bit#(MemTagSize)) tagDone(Bit#(MemTagSize) tag);
      return tuple2(truncate(tag), tag);
   endfunction
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) arbPipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(arbFifo))));
   UnFunnelPipe#(1,numServers,Bit#(MemTagSize),2) donePipes <- mkUnFunnelPipesPipelined(vec(mapPipe(tagDone, toPipeOut(writeDoneFifo))));
   // FIXME: pass arbPipe and donePipe as parameters to mkMemWriteChannel
   for (Integer channel = 0; channel < valueOf(numServers); channel = channel + 1) begin
      mkConnection(arbPipes[channel], writeChannels[channel].writeGnt);
      mkConnection(donePipes[channel], writeChannels[channel].writeDone);
   end

   rule rl_arbitration if (!reqInFlight);
      let req <- toGet(reqFunnel[0]).get();
      // tag is channel number
      arbFifo.enq(req.tag);
      writeReqFifo.enq(req);
      reqInFlight <= True;
   endrule
   rule rl_writeData if (reqInFlight);
      MemData#(userWidth) md <- toGet(dataFunnel[0]).get();
      if (md.last)
	 reqInFlight <= False;
      writeDataFifo.enq(md);
   endrule

   interface writeServers = genWith(writeChannelServer);
   interface MemWriteClient dmaClient;
      interface writeReq = toGet(writeReqFifo);
      interface writeData = toGet(writeDataFifo);
      interface writeDone = toPut(writeDoneFifo);
   endinterface: dmaClient

endmodule


updated copyright notice

updated copyright notice

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

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

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

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

import FIFO::*;

interface EchoIndications;
    method Action heard(Bit#(32) v);
    method Action heard2(Bit#(16) a, Bit#(16) b);
endinterface

interface Echo;
    method Action say(Bit#(32) v);
    method Action say2(Bit#(16) a, Bit#(16) b);
endinterface

typedef struct {
	Bit#(16) a;
	Bit#(16) b;
} EchoPair deriving (Bits);

module mkEcho#(EchoIndications indications)(Echo);
    FIFO#(Bit#(32)) delay <- mkSizedFIFO(8);
    FIFO#(EchoPair) delay2 <- mkSizedFIFO(8);

    rule heard;
        delay.deq;
        indications.heard(delay.first);
    endrule

    rule heard2;
        delay2.deq;
        indications.heard2(delay2.first.b, delay2.first.a);
    endrule

    method Action say(Bit#(32) v);
        delay.enq(v);
    endmethod

    method Action say2(Bit#(16) a, Bit#(16) b);
        delay2.enq(EchoPair { a: a, b: b});
    endmethod

endmodule

// Copyright (c) 2013 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 FIFO::*;

interface EchoIndications;
    method Action heard(Bit#(32) v);
    method Action heard2(Bit#(16) a, Bit#(16) b);
endinterface

interface Echo;
    method Action say(Bit#(32) v);
    method Action say2(Bit#(16) a, Bit#(16) b);
endinterface

typedef struct {
	Bit#(16) a;
	Bit#(16) b;
} EchoPair deriving (Bits);

module mkEcho#(EchoIndications indications)(Echo);
    FIFO#(Bit#(32)) delay <- mkSizedFIFO(8);
    FIFO#(EchoPair) delay2 <- mkSizedFIFO(8);

    rule heard;
        delay.deq;
        indications.heard(delay.first);
    endrule

    rule heard2;
        delay2.deq;
        indications.heard2(delay2.first.b, delay2.first.a);
    endrule

    method Action say(Bit#(32) v);
        delay.enq(v);
    endmethod

    method Action say2(Bit#(16) a, Bit#(16) b);
        delay2.enq(EchoPair { a: a, b: b});
    endmethod

endmodule


Added necessary ProcConfig include to Opcodes

/* Automatically generated by meta-parse.py */

// 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"
`include "Opcodes.defines"

import RVTypes::*;

typedef struct {
    Maybe#(RegType) rs1;
    Maybe#(RegType) rs2;
    Maybe#(RegType) rs3;
    Maybe#(RegType) dst;
    ImmType imm;
} InstType deriving (Bits, Eq, FShow);

function InstType toInstType(Instruction inst);
    Maybe#(RegType) i = tagged Valid Gpr;
    Maybe#(RegType) f = tagged Valid Fpu;
    Maybe#(RegType) n = tagged Invalid;
    InstType ret = (case (inst) matches
            `LUI:           InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: U   };
            `AUIPC:         InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: U   };
            `JAL:           InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: UJ  };
            `JALR:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `BEQ:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BNE:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BLT:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BGE:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BLTU:          InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BGEU:          InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `LB:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LH:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LW:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LBU:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LHU:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SB:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `SH:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `SW:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `ADDI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SLTI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SLTIU:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `XORI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ORI:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ANDI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ADD:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SUB:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLL:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLT:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLTU:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `XOR:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRL:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRA:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `OR:            InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AND:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `FENCE:         InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `FENCE_I:       InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `LWU:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LD:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SD:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `SLLI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRLI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRAI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ADDIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SLLIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRLIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRAIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ADDW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SUBW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLLW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRLW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRAW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MUL:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULH:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULHSU:        InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULHU:         InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIV:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIVU:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REM:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REMU:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIVW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIVUW:         InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REMW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REMUW:         InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `LR_W:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `SC_W:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOSWAP_W:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOADD_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOXOR_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOOR_W:       InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOAND_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMIN_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAX_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMINU_W:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAXU_W:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `LR_D:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `SC_D:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOSWAP_D:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOADD_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOXOR_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOOR_D:       InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOAND_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMIN_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAX_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMINU_D:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAXU_D:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `ECALL:         InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `EBREAK:        InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `URET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `SRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `HRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `MRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `DRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `SFENCE_VM:     InstType{rs1: i, rs2: n, rs3: n, dst: n, imm: None};
            `WFI:           InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `CSRRW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `CSRRS:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `CSRRC:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `CSRRWI:        InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: Z   };
            `CSRRSI:        InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: Z   };
            `CSRRCI:        InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: Z   };
            `FLW:           InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: I   };
            `FSW:           InstType{rs1: i, rs2: f, rs3: n, dst: n, imm: S   };
            `FMADD_S:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FMSUB_S:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMSUB_S:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMADD_S:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FADD_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSUB_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMUL_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FDIV_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJ_S:       InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJN_S:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJX_S:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMIN_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMAX_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSQRT_S:       InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FLE_S:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FLT_S:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FEQ_S:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FCVT_W_S:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_WU_S:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_S_W:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_S_WU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FMV_X_S:       InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCLASS_S:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FMV_S_X:       InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_L_S:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_LU_S:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_S_L:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_S_LU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FLD:           InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: I   };
            `FSD:           InstType{rs1: i, rs2: f, rs3: n, dst: n, imm: S   };
            `FMADD_D:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FMSUB_D:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMSUB_D:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMADD_D:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FADD_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSUB_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMUL_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FDIV_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJ_D:       InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJN_D:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJX_D:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMIN_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMAX_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FCVT_S_D:      InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_D_S:      InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FSQRT_D:       InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FLE_D:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FLT_D:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FEQ_D:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FCVT_W_D:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_WU_D:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_D_W:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_D_WU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCLASS_D:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_L_D:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_LU_D:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FMV_X_D:       InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_D_L:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_D_LU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FMV_D_X:       InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            default:        ?;
        endcase);
    if ((ret.dst == tagged Valid Gpr) && (getInstFields(inst).rd == 0)) begin
        ret.dst = tagged Invalid;
    end
    return ret;
endfunction

/* Automatically generated by meta-parse.py */

// 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 "Opcodes.defines"
import RVTypes::*;

typedef struct {
    Maybe#(RegType) rs1;
    Maybe#(RegType) rs2;
    Maybe#(RegType) rs3;
    Maybe#(RegType) dst;
    ImmType imm;
} InstType deriving (Bits, Eq, FShow);

function InstType toInstType(Instruction inst);
    Maybe#(RegType) i = tagged Valid Gpr;
    Maybe#(RegType) f = tagged Valid Fpu;
    Maybe#(RegType) n = tagged Invalid;
    InstType ret = (case (inst) matches
            `LUI:           InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: U   };
            `AUIPC:         InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: U   };
            `JAL:           InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: UJ  };
            `JALR:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `BEQ:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BNE:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BLT:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BGE:           InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BLTU:          InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `BGEU:          InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: SB  };
            `LB:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LH:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LW:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LBU:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LHU:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SB:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `SH:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `SW:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `ADDI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SLTI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SLTIU:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `XORI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ORI:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ANDI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ADD:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SUB:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLL:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLT:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLTU:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `XOR:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRL:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRA:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `OR:            InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AND:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `FENCE:         InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `FENCE_I:       InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `LWU:           InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `LD:            InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SD:            InstType{rs1: i, rs2: i, rs3: n, dst: n, imm: S   };
            `SLLI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRLI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRAI:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ADDIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SLLIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRLIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `SRAIW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: I   };
            `ADDW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SUBW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SLLW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRLW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `SRAW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MUL:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULH:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULHSU:        InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULHU:         InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIV:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIVU:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REM:           InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REMU:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `MULW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIVW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `DIVUW:         InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REMW:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `REMUW:         InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `LR_W:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `SC_W:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOSWAP_W:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOADD_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOXOR_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOOR_W:       InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOAND_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMIN_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAX_W:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMINU_W:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAXU_W:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `LR_D:          InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `SC_D:          InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOSWAP_D:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOADD_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOXOR_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOOR_D:       InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOAND_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMIN_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAX_D:      InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMINU_D:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `AMOMAXU_D:     InstType{rs1: i, rs2: i, rs3: n, dst: i, imm: None};
            `ECALL:         InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `EBREAK:        InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `URET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `SRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `HRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `MRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `DRET:          InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `SFENCE_VM:     InstType{rs1: i, rs2: n, rs3: n, dst: n, imm: None};
            `WFI:           InstType{rs1: n, rs2: n, rs3: n, dst: n, imm: None};
            `CSRRW:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `CSRRS:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `CSRRC:         InstType{rs1: i, rs2: n, rs3: n, dst: i, imm: None};
            `CSRRWI:        InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: Z   };
            `CSRRSI:        InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: Z   };
            `CSRRCI:        InstType{rs1: n, rs2: n, rs3: n, dst: i, imm: Z   };
            `FLW:           InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: I   };
            `FSW:           InstType{rs1: i, rs2: f, rs3: n, dst: n, imm: S   };
            `FMADD_S:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FMSUB_S:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMSUB_S:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMADD_S:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FADD_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSUB_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMUL_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FDIV_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJ_S:       InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJN_S:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJX_S:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMIN_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMAX_S:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSQRT_S:       InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FLE_S:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FLT_S:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FEQ_S:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FCVT_W_S:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_WU_S:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_S_W:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_S_WU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FMV_X_S:       InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCLASS_S:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FMV_S_X:       InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_L_S:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_LU_S:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_S_L:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_S_LU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FLD:           InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: I   };
            `FSD:           InstType{rs1: i, rs2: f, rs3: n, dst: n, imm: S   };
            `FMADD_D:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FMSUB_D:       InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMSUB_D:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FNMADD_D:      InstType{rs1: f, rs2: f, rs3: f, dst: f, imm: None};
            `FADD_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSUB_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMUL_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FDIV_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJ_D:       InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJN_D:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FSGNJX_D:      InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMIN_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FMAX_D:        InstType{rs1: f, rs2: f, rs3: n, dst: f, imm: None};
            `FCVT_S_D:      InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_D_S:      InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FSQRT_D:       InstType{rs1: f, rs2: n, rs3: n, dst: f, imm: None};
            `FLE_D:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FLT_D:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FEQ_D:         InstType{rs1: f, rs2: f, rs3: n, dst: i, imm: None};
            `FCVT_W_D:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_WU_D:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_D_W:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_D_WU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCLASS_D:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_L_D:      InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_LU_D:     InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FMV_X_D:       InstType{rs1: f, rs2: n, rs3: n, dst: i, imm: None};
            `FCVT_D_L:      InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FCVT_D_LU:     InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            `FMV_D_X:       InstType{rs1: i, rs2: n, rs3: n, dst: f, imm: None};
            default:        ?;
        endcase);
    if ((ret.dst == tagged Valid Gpr) && (getInstFields(inst).rd == 0)) begin
        ret.dst = tagged Invalid;
    end
    return ret;
endfunction