update packetbuff top

update packetbuff top

package TbTop;

import BuildVector::*;
import GetPut::*;
import ClientServer::*;
import DefaultValue::*;
import StmtFSM::*;
import FIFO::*;
import Pipe::*;
import Vector::*;
import ConnectalMemory::*;

import MemTypes::*;
import MemServerIndication::*;
import MMUIndication::*;
import SharedBuff::*;
import Ethernet::*;
import PacketBuffer::*;

import Malloc::*;

typedef 12 PktSize; // maximum 4096b
typedef TDiv#(`DataBusWidth, 32) WordsPerBeat;

interface TbIndication;
   method Action read_version_resp(Bit#(32) version);
   method Action malloc_resp(Bit#(32) sglId);
endinterface

interface TbRequest;
   method Action read_version();
   method Action allocPacketBuff(Bit#(PktSize) sz);
   method Action readPacketBuff(Bit#(16) addr);
   method Action writePacketBuff(Bit#(16) addr, Bit#(64) data);
   method Action freePacketBuff(Bit#(32) id);
   method Action writePacketData(Vector#(2, Bit#(64)) data, Vector#(2, Bit#(8)) mask, Bit#(1) sop, Bit#(1) eop);
endinterface

interface TbTop;
   interface TbRequest request;
endinterface
module mkTbTop#(TbIndication indication, ConnectalMemory::MemServerIndication memServerIndication, Malloc::MallocIndication mallocIndication)(TbTop);

   let verbose = True;
   // read client interface
   FIFO#(MemRequest) readReqFifo <-mkSizedFIFO(4);
   FIFO#(MemData#(`DataBusWidth)) readDataFifo <- mkSizedFIFO(32);
   MemReadClient#(`DataBusWidth) dmaReadClient = (interface MemReadClient;
   interface Get readReq = toGet(readReqFifo);
   interface Put readData = toPut(readDataFifo);
   endinterface);

   // write client interface
   FIFO#(MemRequest) writeReqFifo <- mkSizedFIFO(4);
   FIFO#(MemData#(`DataBusWidth)) writeDataFifo <- mkSizedFIFO(32);
   FIFO#(Bit#(MemTagSize)) writeDoneFifo <- mkSizedFIFO(4);
   MemWriteClient#(`DataBusWidth) dmaWriteClient = (interface MemWriteClient;
   interface Get writeReq = toGet(writeReqFifo);
   interface Get writeData = toGet(writeDataFifo);
   interface Put writeDone = toPut(writeDoneFifo);
   endinterface);

   SharedBuffer#(12, 128, 1) buff <- mkSharedBuffer(vec(dmaReadClient), vec(dmaWriteClient), memServerIndication, mallocIndication);
   PacketBuffer ring_buff <- mkPacketBuffer();

   interface TbRequest request;
      method Action read_version();
         let v= `NicVersion;
         indication.read_version_resp(v);
      endmethod

      method Action allocPacketBuff(Bit#(PktSize) sz);
         if (verbose) $display("TbTop allocPacketBuff: %d", sz);
         buff.malloc(sz);
      endmethod

      method Action readPacketBuff(Bit#(16) addr);
         Bit#(ByteEnableSize) firstbe = 'hffff;
         Bit#(ByteEnableSize) lastbe = 'hffff;
         readReqFifo.enq(MemRequest {sglId: 0, offset: 0, burstLen: 16, tag:0, firstbe: firstbe, lastbe: lastbe});
      endmethod

      method Action writePacketBuff(Bit#(16) addr, Bit#(64) data);
         Bit#(ByteEnableSize) firstbe = 'hffff;
         Bit#(ByteEnableSize) lastbe = 'hffff;
         writeReqFifo.enq(MemRequest {sglId: 0, offset:0, burstLen: 16, tag:0, firstbe: firstbe, lastbe: lastbe});

         function Bit#(8) plusi(Integer i); return fromInteger(i); endfunction
         Vector#(TMul#(4, WordsPerBeat), Bit#(8)) v = genWith(plusi);
         $display("TbTop writePacketBuff: %x", v);
         writeDataFifo.enq(MemData {data: pack(v), tag:0, last:True});
      endmethod

      method Action freePacketBuff(Bit#(32) id);

      endmethod

      method Action writePacketData(Vector#(2, Bit#(64)) data, Vector#(2, Bit#(8)) mask, Bit#(1) sop, Bit#(1) eop);
         EtherData beat = defaultValue;
         beat.data = pack(reverse(data));
         beat.mask = pack(reverse(mask));
         beat.sop = unpack(sop);
         beat.eop = unpack(eop);
         ring_buff.writeServer.writeData.put(beat);
      endmethod

   endinterface
endmodule: mkTbTop

endpackage: TbTop

package TbTop;

import BuildVector::*;
import GetPut::*;
import ClientServer::*;
import StmtFSM::*;
import FIFO::*;
import Pipe::*;
import Vector::*;
import ConnectalMemory::*;

import MemTypes::*;
import MemServerIndication::*;
import MMUIndication::*;
import SharedBuff::*;

import Malloc::*;

typedef 12 PktSize; // maximum 4096b
typedef TDiv#(`DataBusWidth, 32) WordsPerBeat;

interface TbIndication;
   method Action read_version_resp(Bit#(32) version);
   method Action malloc_resp(Bit#(32) sglId);
endinterface

interface TbRequest;
   method Action read_version();
   method Action allocPacketBuff(Bit#(PktSize) sz);
   method Action readPacketBuff(Bit#(16) addr);
   method Action writePacketBuff(Bit#(16) addr, Bit#(64) data);
   method Action freePacketBuff(Bit#(32) id);
endinterface

interface TbTop;
   interface TbRequest request;
endinterface
module mkTbTop#(TbIndication indication, ConnectalMemory::MemServerIndication memServerIndication, Malloc::MallocIndication mallocIndication)(TbTop);

   let verbose = True;
   // read client interface
   FIFO#(MemRequest) readReqFifo <-mkSizedFIFO(4);
   FIFO#(MemData#(`DataBusWidth)) readDataFifo <- mkSizedFIFO(32);
   MemReadClient#(`DataBusWidth) dmaReadClient = (interface MemReadClient;
   interface Get readReq = toGet(readReqFifo);
   interface Put readData = toPut(readDataFifo);
   endinterface);

   // write client interface
   FIFO#(MemRequest) writeReqFifo <- mkSizedFIFO(4);
   FIFO#(MemData#(`DataBusWidth)) writeDataFifo <- mkSizedFIFO(32);
   FIFO#(Bit#(MemTagSize)) writeDoneFifo <- mkSizedFIFO(4);
   MemWriteClient#(`DataBusWidth) dmaWriteClient = (interface MemWriteClient;
   interface Get writeReq = toGet(writeReqFifo);
   interface Get writeData = toGet(writeDataFifo);
   interface Put writeDone = toPut(writeDoneFifo);
   endinterface);

   SharedBuffer#(12, 128, 1) buff <- mkSharedBuffer(vec(dmaReadClient), vec(dmaWriteClient), memServerIndication, mallocIndication);

   interface TbRequest request;
      method Action read_version();
         let v= `NicVersion;
         indication.read_version_resp(v);
      endmethod

      method Action allocPacketBuff(Bit#(PktSize) sz);
         if (verbose) $display("TbTop allocPacketBuff: %d", sz);
         buff.malloc(sz);
      endmethod

      method Action readPacketBuff(Bit#(16) addr);
         Bit#(ByteEnableSize) firstbe = 'hffff;
         Bit#(ByteEnableSize) lastbe = 'hffff;
         readReqFifo.enq(MemRequest {sglId: 0, offset: 0, burstLen: 16, tag:0, firstbe: firstbe, lastbe: lastbe});
      endmethod

      method Action writePacketBuff(Bit#(16) addr, Bit#(64) data);
         Bit#(ByteEnableSize) firstbe = 'hffff;
         Bit#(ByteEnableSize) lastbe = 'hffff;
         writeReqFifo.enq(MemRequest {sglId: 0, offset:0, burstLen: 16, tag:0, firstbe: firstbe, lastbe: lastbe});

         function Bit#(8) plusi(Integer i); return fromInteger(i); endfunction
         Vector#(TMul#(4, WordsPerBeat), Bit#(8)) v = genWith(plusi);
         $display("TbTop writePacketBuff: %x", v);
         writeDataFifo.enq(MemData {data: pack(v), tag:0, last:True});
      endmethod

      method Action freePacketBuff(Bit#(32) id);

      endmethod
   endinterface
endmodule: mkTbTop

endpackage: TbTop


connect tx_empty

connect tx_empty

// Copyright (c) 2014 Cornell University.

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

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

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

package EthMac;

import Clocks::*;
import Vector::*;
import Connectable                   ::*;
import Pipe                          ::*;
import FIFOF                         ::*;
import GetPut                        ::*;
import Pipe::*;
import DefaultValue::*;
import OInt::*;

import AlteraMacWrap::*;
import Ethernet::*;

interface EthMacIfc;
   (* always_ready, always_enabled *)
   method Bit#(72) tx;
   (* always_ready, always_enabled *)
   method Action rx (Bit#(72) v);
   interface Put#(PacketDataT#(64)) packet_tx;
   interface Get#(PacketDataT#(64)) packet_rx;
endinterface

typedef struct {
   Bit#(n) data;
   Bit#(TDiv#(n, 8)) mask;
   Bit#(1) sop;
   Bit#(1) eop;
} PacketDataT#(numeric type n) deriving (Bits,Eq);

instance DefaultValue#(PacketDataT#(64));
    defaultValue = PacketDataT {
        data : 0,
        mask : 0,
        sop : 0,
        eop : 0
    };
endinstance

// Mac Wrapper
(* synthesize *)
module mkEthMac#(Clock clk_50, Clock clk_156_25, Clock rx_clk, Reset rst_156_25_n)(EthMacIfc);
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;

   Reset rx_rst_n <- mkAsyncReset(2, rst_156_25_n, rx_clk);
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, clk_50);

   // Wire data_dw
   Wire#(Maybe#(Bit#(64))) tx_data_w <- mkDWire(tagged Invalid, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(3)) tx_empty_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_ready_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_sop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_eop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);

   FIFOF#(PacketDataT#(64)) rx_fifo <- mkFIFOF(clocked_by rx_clk, reset_by rx_rst_n);

   MacWrap mac <- mkMacWrap(clk_50, clk_156_25, rx_clk, rst_50_n, rst_156_25_n, rx_rst_n, clocked_by clk_156_25, reset_by rst_156_25_n);

   rule tx_ready;
      tx_ready_w <= mac.tx.fifo_in_ready();
   endrule

   rule tx_data;
      mac.tx.fifo_in_data(fromMaybe(0,tx_data_w));
   endrule

   rule tx_sop;
      mac.tx.fifo_in_startofpacket(tx_sop_w);
   endrule

   rule tx_eop;
      mac.tx.fifo_in_endofpacket(tx_eop_w);
   endrule

   rule tx_empty;
      mac.tx.fifo_in_empty(tx_empty_w);
   endrule

   rule tx_error;
      mac.tx.fifo_in_error(1'b0);
   endrule

   rule tx_valid;
      mac.tx.fifo_in_valid(pack(isValid(tx_data_w)));
   endrule

   rule rx_data;
      let valid = mac.rx.fifo_out_valid();

      PacketDataT#(64) packet = defaultValue;
      packet.data = mac.rx.fifo_out_data();
      packet.sop = mac.rx.fifo_out_startofpacket();
      packet.eop = mac.rx.fifo_out_endofpacket();
      packet.mask = 1<<mac.rx.fifo_out_empty() - 1;

      if (valid == 1'b1) begin
         rx_fifo.enq(packet);
      end
   endrule

   rule rx_ready;
      mac.rx.fifo_out_ready(pack(rx_fifo.notFull));
   endrule

   method tx = mac.xgmii.tx_data;
   method Action rx(x) = mac.xgmii.rx_data(x);
   interface Put packet_tx;
      method Action put(PacketDataT#(64) d) if (tx_ready_w != 0);
         Bit#(3) tx_empty = truncate(fromOInt(unpack(d.mask+1)));
         tx_data_w <= tagged Valid pack(d.data);
         tx_empty_w <= tx_empty;
         tx_sop_w <= pack(d.sop);
         tx_eop_w <= pack(d.eop);
         $display("tx_empty %h", tx_empty);
      endmethod
   endinterface
   interface Get packet_rx = toGet(rx_fifo);
endmodule
endpackage: EthMac

// Copyright (c) 2014 Cornell University.

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

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

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

package EthMac;

import Clocks::*;
import Vector::*;
import Connectable                   ::*;
import Pipe                          ::*;
import FIFOF                         ::*;
import GetPut                        ::*;
import Pipe::*;
import DefaultValue::*;
import OInt::*;

import AlteraMacWrap::*;
import Ethernet::*;

interface EthMacIfc;
   (* always_ready, always_enabled *)
   method Bit#(72) tx;
   (* always_ready, always_enabled *)
   method Action rx (Bit#(72) v);
   interface Put#(PacketDataT#(64)) packet_tx;
   interface Get#(PacketDataT#(64)) packet_rx;
endinterface

typedef struct {
   Bit#(n) data;
   Bit#(TDiv#(n, 8)) mask;
   Bit#(1) sop;
   Bit#(1) eop;
} PacketDataT#(numeric type n) deriving (Bits,Eq);

instance DefaultValue#(PacketDataT#(64));
    defaultValue = PacketDataT {
        data : 0,
        mask : 0,
        sop : 0,
        eop : 0
    };
endinstance

// Mac Wrapper
(* synthesize *)
module mkEthMac#(Clock clk_50, Clock clk_156_25, Clock rx_clk, Reset rst_156_25_n)(EthMacIfc);
   Clock defaultClock <- exposeCurrentClock;
   Reset defaultReset <- exposeCurrentReset;

   Reset rx_rst_n <- mkAsyncReset(2, rst_156_25_n, rx_clk);
   Reset rst_50_n <- mkAsyncReset(2, defaultReset, clk_50);

   // Wire data_dw
   Wire#(Maybe#(Bit#(64))) tx_data_w <- mkDWire(tagged Invalid, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(3)) tx_empty_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_ready_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_sop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);
   Wire#(Bit#(1)) tx_eop_w <- mkDWire(0, clocked_by clk_156_25, reset_by rst_156_25_n);

   FIFOF#(PacketDataT#(64)) rx_fifo <- mkFIFOF(clocked_by rx_clk, reset_by rx_rst_n);

   MacWrap mac <- mkMacWrap(clk_50, clk_156_25, rx_clk, rst_50_n, rst_156_25_n, rx_rst_n, clocked_by clk_156_25, reset_by rst_156_25_n);

   rule tx_ready;
      tx_ready_w <= mac.tx.fifo_in_ready();
   endrule

   rule tx_data;
      mac.tx.fifo_in_data(fromMaybe(0,tx_data_w));
   endrule

   rule tx_sop;
      mac.tx.fifo_in_startofpacket(tx_sop_w);
   endrule

   rule tx_eop;
      mac.tx.fifo_in_endofpacket(tx_eop_w);
   endrule

   rule tx_valid;
      mac.tx.fifo_in_valid(pack(isValid(tx_data_w)));
   endrule

   rule rx_data;
      let valid = mac.rx.fifo_out_valid();

      PacketDataT#(64) packet = defaultValue;
      packet.data = mac.rx.fifo_out_data();
      packet.sop = mac.rx.fifo_out_startofpacket();
      packet.eop = mac.rx.fifo_out_endofpacket();
      packet.mask = 1<<mac.rx.fifo_out_empty() - 1;

      if (valid == 1'b1) begin
         rx_fifo.enq(packet);
      end
   endrule

   rule rx_ready;
      mac.rx.fifo_out_ready(pack(rx_fifo.notFull));
   endrule

   method tx = mac.xgmii.tx_data;
   method Action rx(x) = mac.xgmii.rx_data(x);
   interface Put packet_tx;
      method Action put(PacketDataT#(64) d) if (tx_ready_w != 0);
         tx_data_w <= tagged Valid pack(d.data);
         tx_empty_w <= truncate(fromOInt(unpack(d.mask+1)));
         tx_sop_w <= pack(d.sop);
         tx_eop_w <= pack(d.eop);
      endmethod
   endinterface
   interface Get packet_rx = toGet(rx_fifo);
endmodule
endpackage: EthMac


cleanup

cleanup

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

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

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

import Connectable::*;
import SerialFIFO::*;
import LinkHost::*;
import FIFOF::*;
import Vector::*;

typedef struct {
	Bit#(4) address;
	Bit#(4) lsn;
	Bit#(64) payload;
	} DataMessage deriving(Bits);

interface NocNode#(type a);
   interface LinkHost#(a) host;
endinterface

function Action movetolink(FIFOF#(DataMessage) from, SerialFIFOIn#(DataMessage) to);
   return action
	     to.enq(from.first);
	     from.deq();
	  endaction;
endfunction

function Action outputarbitrate(FIFOF#(DataMessage) a,
				FIFOF#(DataMessage) b,
			       Reg#(Bool) select,
			       SerialFIFOIn#(DataMessage) r);
   return action
	     if (a.notEmpty && !b.notEmpty)
		movetolink(a, r);
	     else if (!a.notEmpty && b.notEmpty)
		movetolink(b, r);
	     else if (a.notEmpty && b.notEmpty)
		begin
		   if (select)
		      movetolink(a, r);
		   else
		      movetolink(b, r);
		   select <= select != True;
		end
	  endaction;
endfunction

module mkNocNode#(Bit#(4) id,
   SerialFIFO#(DataMessage) east,
   SerialFIFO#(DataMessage) west)(NocNode#(a))
   provisos(Bits#(a,asize),
            Log#(asize, k));

   // out Links
   LinkHost#(DataMessage) lhost <- mkLinkHost(id);

   // buffers for crossbar switch

   FIFOF#(DataMessage) he <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) hw <- mkSizedFIFOF(4);

   FIFOF#(DataMessage) ew <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) we <- mkSizedFIFOF(4);

   FIFOF#(DataMessage) eh <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) wh <- mkSizedFIFOF(4);

   // sort host messages to proper queue

   rule fromhost;
      if (lhost.tonet.first.address < id)
	 move(lhost.tonet, hw);
      else if (lhost.tonet.first.address == id)
	 move(lhost.tonet, lhost.tohost);
      else
	 move(lhost.tonet, he);
   endrule

   // arbiter to send data messages to w

   Bit#(1) owselect <- mkReg(0);

   rule genow;
      outputarbitrate(ew, hw, owselect, low);
   endrule

   // arbiter to send data messages to e

   Bit#(1) oeselect <- mkReg(0);

   rule genoe;
      outputarbitrate(we, he, oeselect, loe);
   endrule

   // Handle arriving messages from East

   rule fromeast;
      if (east.first.address == id)
	 eh.enq(east.first);
      else
	 ew.enq(east.first);
      east.deq();
      endrule

   // Handle arriving messages from West

   rule fromwest;
      if (west.first.address == id)
	 wh.enq(west.first);
      else
	 we.enq(west.first);
      west.deq();
      endrule

  // interface wiring

   interface LinkHost host = lhost;

endmodule

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

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

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

import Connectable::*;
import SerialFIFO::*;
import LinkHost::*;
import FIFOF::*;
import Vector::*;

/* This is a serial to parallel converter for messages of type a
 * The data register is assumed to always be available, so an arriving
 * message must be removed ASAP or be overwritten
 */

typedef struct {
	Bit#(4) address;
	Bit#(4) lsn;
	Bit#(64) payload;
	} DataMessage deriving(Bits);

interface NocNode#(type a);
   interface LinkHost#(a) host;
endinterface

function Action movetolink(FIFOF#(DataMessage) from, SerialFIFOIn#(DataMessage) to);
   return action
	     to.enq(from.first);
	     from.deq();
	  endaction;
endfunction

function Action outputarbitrate(FIFOF#(DataMessage) a,
				FIFOF#(DataMessage) b,
			       Reg#(Bool) select,
			       SerialFIFOIn#(DataMessage) r);
   return action
	     if (a.notEmpty && !b.notEmpty)
		movetolink(a, r);
	     else if (!a.notEmpty && b.notEmpty)
		movetolink(b, r);
	     else if (a.notEmpty && b.notEmpty)
		begin
		   if (select)
		      movetolink(a, r);
		   else
		      movetolink(b, r);
		   select <= select != True;
		end
	  endaction;
endfunction

module mkNocNode#(Bit#(4) id,
   SerialFIFO#(DataMessage) east,
   SerialFIFO#(DataMessage) west)(NocNode#(a))
   provisos(Bits#(a,asize),
            Log#(asize, k));

   // out Links
   LinkHost#(DataMessage) lhost <- mkLinkHost(id);

   // buffers for crossbar switch

   FIFOF#(DataMessage) he <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) hw <- mkSizedFIFOF(4);

   FIFOF#(DataMessage) ew <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) we <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) eh <- mkSizedFIFOF(4);
   FIFOF#(DataMessage) wh <- mkSizedFIFOF(4);

   // sort host messages to proper queue

   rule fromhost;
      if (lhost.tonet.first.address < id)
	 move(lhost.tonet, hw);
      else if (lhost.tonet.first.address == id)
	 move(lhost.tonet, lhost.tohost);
      else
	 move(lhost.tonet, he);
   endrule

   // arbiter to send data messages to e

   Bit#(1) owselect <- mkReg(0);
   Bit#(1) oeselect <- mkReg(0);

   rule genow;
      outputarbitrate(ew, hw, owselect, low);
   endrule

   // arbiter to send data messages to w

   rule genoe;
      outputarbitrate(we, he, oeselect, loe);
   endrule

   // Handle arriving messages from East

   rule fromeast;
      if (east.first.address == id)
	 eh.enq(east.first);
      else
	 ew.enq(east.first);
      east.deq();
      endrule

   // Handle arriving messages from West

   rule fromwest;
      if (west.first.address == id)
	 wh.enq(west.first);
      else
	 we.enq(west.first);
      west.deq();
      endrule

  // interface wiring

   interface LinkHost host = lhost;

endmodule


change CopyEngine to an interface which accepts and returns 8 word blocks

// 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 ClientServer::*;
import PortalRMemory::*;
import RingTypes::*;

// The interface to the copyengine is a pair of fifos which supply and accept
// blocks of 8 64 bit words

module mkCopyEngine#(ReadChan#(Bit#(64)) copy_read_chan, WriteChan#(Bit#(64)) copy_write_chan) ( Server#(Bit#(64), Bit#(64)));
   FIFO#(CommandStruct) f_in  <- mkFIFO;    // to buffer incoming requests
   FIFO#(Bit#(32)) f_out <- mkFIFO;    // to buffer outgoing responses
   Reg#(Bit#(16)) copyReadCount <- mkReg(0);
   Reg#(Bit#(16)) copyWriteCount <- mkReg(0);
   Reg#(Bit#(40)) copyReadAddr <- mkReg(0);
   Reg#(Bit#(40)) copyWriteAddr <- mkReg(0);
   Reg#(Bit#(32)) copyTag <- mkReg(0);
   Reg#(Bool) copyBusy <- mkReg(False);

   Stmt CopyStart = while(True)
   seq
      while (copyBusy) noAction;
      copyTag <= f_in.deq[31:0];
      copyReadAddr <= f_in.deq[39:0];
      copyWriteAddr <= f_in.deq[39:0];
      action
	 let regv <-f_in.deq[15:0];
	 copyReadCount <= regv;
	 copyWriteCount <= regv;
      endaction
      for (ii <= 0; ii < 4; ii <= ii+1)
	 f_in.deq;
      copyBusy <= True;
   endseq

    rule copyReadRule (copyBusy && (copyReadCount != 0));
       $display("copyRead %h, count %h", copyReadAddr, copyReadCount);
       copy_read_chan.readReq.put(copyReadAddr);
       copyReadAddr <= copyReadAddr + 8;
       copyReadCount <= copyReadCount - 8;
    endrule

    rule copyReadWriteRule (copyBusy);
       let data <- copy_read_chan.readData.get;
       $display("copyReadWrite addr %h", copyWriteAddr);
       copy_write_chan.writeReq.put(copyWriteAddr);
       copy_write_chan.writeData.put(data);
       copyWriteAddr <= copyWriteAddr + 8;
    endrule

   Stmt copyFinish = while(True)
   seq
      while (!copyBusy) noAction;
      while (copyWriteCount > 0)
      action
	 let v <= copy_write_chan.writeDone.get;
	 copyWriteCount <= copyWriteCount - 8;
      endaction
      for (ii <= 0; ii < 7; ii += 1)
	 f_out.enq(0);
      f_out.enq(extend(copyTag));
      copyBusy >= False;
   endseq

   interface Put request = toPut(f_in);
   interface Get response = toGet (f_out);

endmodule: mkCopyEngine

// 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 ClientServer::*;
import PortalRMemory::*;
import RingTypes::*;

module mkCopyEngine#(ReadChan#(Bit#(64)) copy_read_chan, WriteChan#(Bit#(64)) copy_write_chan) ( Server#(CommandStruct, Bit#(32)));
    FIFO#(CommandStruct) f_in  <- mkFIFO;    // to buffer incoming requests
    FIFO#(Bit#(32)) f_out <- mkFIFO;    // to buffer outgoing responses
    Reg#(Bit#(16)) copyReadCount <- mkReg(0);
    Reg#(Bit#(16)) copyWriteCount <- mkReg(0);
    Reg#(Bit#(40)) copyReadAddr <- mkReg(0);
    Reg#(Bit#(40)) copyWriteAddr <- mkReg(0);
    Reg#(Bit#(32)) copyTag <- mkReg(0);
    Reg#(Bool) copyBusy <- mkReg(False);

    rule copyReadRule (copyBusy && (copyReadCount != 0));
       $display("copyRead %h, count %h", copyReadAddr, copyReadCount);
       copy_read_chan.readReq.put(copyReadAddr);
       copyReadAddr <= copyReadAddr + 8;
       copyReadCount <= copyReadCount - 8;
    endrule

    rule copyReadWriteRule (copyBusy);
       let data <- copy_read_chan.readData.get;
       $display("copyReadWrite addr %h", copyWriteAddr);
       copy_write_chan.writeReq.put(copyWriteAddr);
       copy_write_chan.writeData.put(data);
       copyWriteAddr <= copyWriteAddr + 8;
    endrule

    rule copyWriteCompleteRule (copyBusy);
       let v <- copy_write_chan.writeDone.get;
       $display("copyWrite count %h", copyWriteCount);
       if (copyWriteCount == 8) begin
	  copyBusy <= False;
	  f_out.enq(copyTag);
       end
       copyWriteCount <= copyWriteCount - 8;
    endrule

    rule copyStart (!copyBusy);
       let cmd = f_in.first;
       $display("doCopy %h %h %h", cmd.fromAddress, cmd.toAddress, cmd.count);
       copyReadAddr <= cmd.fromAddress;
       copyWriteAddr <= cmd.toAddress;
       copyReadCount <= cmd.count;
       copyWriteCount <= cmd.count;
       copyTag <= cmd.tag;
       copyBusy <= True;
       f_in.deq();
    endrule

   interface Put request = toPut(f_in);
   interface Get response = toGet (f_out);
endmodule: mkCopyEngine


Removed unused code

Removed unused code

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

import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import GetPut::*;
import Vector::*;

import Abstraction::*;
import RegUtil::*;
import RVRFile::*;
import RVCsrFile::*;
import RVExec::*;
import RVFpu::*;
import RVMulDiv::*;
import RVTypes::*;
import VerificationPacket::*;

import RVAlu::*;
import RVControl::*;
import RVDecode::*;
import RVMemory::*;

// This interface is the combination of FrontEnd and BackEnd
interface Core;
    method Action start(Addr startPc);
    method Action stop;

    method ActionValue#(VerificationPacket) getVerificationPacket;
    method ActionValue#(VMInfo) updateVMInfoI;
    method ActionValue#(VMInfo) updateVMInfoD;

    interface Client#(FenceReq, FenceResp) fence;
endinterface

instance Connectable#(Core, MemorySystem);
    module mkConnection#(Core core, MemorySystem mem)(Empty);
        mkConnection(core.fence, mem.fence);
        mkConnection(toGet(core.updateVMInfoI), toPut(mem.updateVMInfoI));
        mkConnection(toGet(core.updateVMInfoD), toPut(mem.updateVMInfoD));
    endmodule
endinstance

typedef enum {
    Wait,
    IMMU,
    IF,
    Dec,
    RegRead,
    Execute,
    Mem,
    WB,
    Trap,
    Trap2
} ProcState deriving (Bits, Eq, FShow);

module mkMulticycleCore#(
        Server#(RVIMMUReq, RVIMMUResp) ivat,
        Server#(RVIMemReq, RVIMemResp) ifetch,
        Server#(RVDMMUReq, RVDMMUResp) dvat,
        Server#(RVDMemReq, RVDMemResp) dmem,
        Bool ipi,
        Bool timerInterrupt,
        Data timer,
        Bool externalInterrupt,
        Data hartID
    )
        (Core);
    let verbose = False;
    File fout = stdout;

    ArchRFile rf <- mkArchRFile;
    RVCsrFile csrf <- mkRVCsrFile(hartID, timer, timerInterrupt, ipi, externalInterrupt);
    MulDivExec mulDiv <- mkBoothRoughMulDivExec;
    FpuExec fpu <- mkFpuExecPipeline;

    Reg#(Bool) running <- mkReg(False);
    Reg#(ProcState) state <- mkReg(Wait);

    Reg#(Addr) pc <- mkReg(0);
    Reg#(Maybe#(ExceptionCause)) exception <- mkReg(tagged Invalid);
    Reg#(Instruction) inst <- mkReg(0);
    Reg#(RVDecodedInst) dInst <- mkReg(unpack(0));
    Reg#(FrontEndCsrs) csrState <- mkReadOnlyReg( FrontEndCsrs { vmI: csrf.vmI, state: csrf.csrState } );

    Reg#(Data) rVal1 <- mkReg(0);
    Reg#(Data) rVal2 <- mkReg(0);
    Reg#(Data) rVal3 <- mkReg(0);
    Reg#(Data) data <- mkReg(0);
    Reg#(Data) addr <- mkReg(0);
    Reg#(Data) nextPc <- mkReg(0);

    FIFO#(VerificationPacket) verificationPackets <- mkFIFO1;

    rule doInstMMU(running && state == IMMU);
        // request address translation from MMU
        ivat.request.put(pc);
        // reset states
        inst <= unpack(0);
        dInst <= unpack(0);
        exception <= tagged Invalid;
        // go to InstFetch stage
        state <= IF;
    endrule

    rule doInstFetch(state == IF);
        // I wanted notation like this:
        // let {addr: .phyPc, exception: .exMMU} = mmuResp.first;
        let resp <- ivat.response.get;
        let phyPc = resp.addr;
        let exMMU = resp.exception;

        if (!isValid(exMMU)) begin
            // no translation exception
            ifetch.request.put(phyPc);
            // go to decode stage
            state <= Dec;
        end else begin
            // translation exception (instruction access fault)
            exception <= exMMU;
            // send instruction to backend
            state <= Trap;
        end
    endrule

    rule doDecode(state == Dec);
        let fInst <- ifetch.response.get;

        let decInst = decodeInst(fInst);

        if (decInst matches tagged Valid .validDInst) begin
            // Legal instruction
            dInst <= validDInst;
        end else begin
            // Illegal instruction
            exception <= tagged Valid IllegalInst;
        end

        inst <= fInst;
        state <= isValid(decInst) ? RegRead : Trap;
    endrule

    rule doRegRead(state == RegRead);
        rVal1 <= rf.rd1(toFullRegIndex(dInst.rs1, getInstFields(inst).rs1));
        rVal2 <= rf.rd2(toFullRegIndex(dInst.rs2, getInstFields(inst).rs2));
        rVal3 <= rf.rd3(toFullRegIndex(dInst.rs3, getInstFields(inst).rs3));
        state <= Execute;
    endrule

    rule doExecute(state == Execute);
        let dataEx = 0;
        let addrEx = 0;
        let nextPcEx = pc + 4;

        Maybe#(Data) imm = getImmediate(dInst.imm, dInst.inst);
        case (dInst.execFunc) matches
            tagged Alu    .aluInst:
                begin
                    dataEx = execAluInst(aluInst, rVal1, rVal2, imm, pc);
                end
            tagged Br     .brFunc:
                begin
                    // data for jal
                    dataEx = pc + 4;
                    nextPcEx = execControl(brFunc, rVal1, rVal2, imm, pc);
                end
            tagged Mem    .memInst:
                begin
                    // data for store and AMO
                    dataEx = rVal2;
                    addrEx = addrCalc(rVal1, imm);
                    dvat.request.put(RVDMMUReq {addr: addrEx, size: memInst.size, op: (memInst.op matches tagged Mem .memOp ? memOp : St)});
                end
            tagged MulDiv .mulDivInst: mulDiv.exec(mulDivInst, rVal1, rVal2);
            tagged Fence  .fenceInst:  noAction;
            // TODO: Handle dynamic rounding mode
            tagged Fpu    .fpuInst:    fpu.exec(fpuInst, getInstFields(inst).rm, rVal1, rVal2, rVal3);
            tagged System .systemInst:
                begin
                    // data for CSR instructions
                    dataEx = fromMaybe(rVal1, imm);
                end
        endcase

        data <= dataEx;
        addr <= addrEx;
        nextPc <= nextPcEx;

        state <= dInst.execFunc matches tagged Mem .* ? Mem : WB;
    endrule

    rule doMem(state == Mem);
        let resp <- dvat.response.get;
        let pAddr = resp.addr;
        let exMMU = resp.exception;

        // TODO: make this type safe! get rid of .Mem accesses to tagged union
        if (!isValid(exMMU)) begin
            dmem.request.put( RVDMemReq {
                    op: dInst.execFunc.Mem.op,
                    size: dInst.execFunc.Mem.size,
                    isUnsigned: dInst.execFunc.Mem.isUnsigned,
                    addr: pAddr,
                    data: data } );
            state <= WB;
        end else begin
            exception <= exMMU;
            state <= Trap;
        end
    endrule

    rule doWB(state == WB);
        let dataWb = data;
        let addrWb = addr;
        let nextPcWb = nextPc;
        let fflagsWb = 0;
        let exceptionWB = exception;

        case(dInst.execFunc) matches
            tagged MulDiv .*: begin
                    dataWb = mulDiv.result_data();
                    mulDiv.result_deq;
                end
            tagged Fpu .*: begin
                    let fpuResult = toFullResult(fpu.result_data);
                    dataWb = fpuResult.data;
                    fflagsWb = fpuResult.fflags;
                    fpu.result_deq;
                end
            tagged Mem .memInst:
                begin
                    if (getsResponse(memInst.op)) begin
                        dataWb <- dmem.response.get;
                    end
                end
        endcase

        Maybe#(TrapCause) trap = tagged Invalid;
        if (exceptionWB matches tagged Valid .validException) begin
            trap = tagged Valid (tagged Exception validException);
        end else if ((nextPcWb & 'b011) != 0) begin
            trap = tagged Valid (tagged Exception InstAddrMisaligned);
        end

        if (dInst.execFunc matches tagged Mem .*) begin
            // don't bother checking for interrupts since you just did a memory operation
        end else begin
            // check for interrupts (this overwrites current exceptions)
            if (csrf.readyInterrupt matches tagged Valid .validInterrupt) begin
                trap = tagged Valid (tagged Interrupt validInterrupt);
            end
        end
        Bool extensionDirty = False;
        Bool fpuDirty = (dInst.dst == tagged Valid Fpu);
        let csrfResult <- csrf.wr(
                pc,
                // performing system instructions
                dInst.execFunc matches tagged System .sysInst ? tagged Valid sysInst : tagged Invalid,
                getInstFields(inst).csr,
                dataWb, // either rf[rs1] or zimm, computed in basicExec
                addrWb,
                // handling exceptions
                trap,
                // indirect writes
                fflagsWb,
                fpuDirty,
                extensionDirty);

        Maybe#(Addr) maybeNextPc = tagged Invalid;
        Maybe#(Data) maybeData = tagged Invalid;
        Maybe#(TrapCause) maybeTrap = tagged Invalid;
        case (csrfResult) matches
            tagged Exception .exc:
                begin
                    maybeNextPc = tagged Valid exc.trapHandlerPC;
                    maybeTrap = tagged Valid exc.exception;
                end
            tagged RedirectPC .newPc:
                maybeNextPc = tagged Valid newPc;
            tagged CsrData .data:
                maybeData = tagged Valid data;
            tagged None:
                noAction;
        endcase

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(nextPcWb, maybeNextPc),
                data: fromMaybe(dataWb, maybeData),
                addr: addr,
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        if (maybeNextPc matches tagged Valid .replayPc) begin
            // This instruction didn't retire

            // redirect happens in Trap2
            nextPc <= replayPc;
            state <= Trap2;
        end else begin
            // This instruction retired
            // write to the register file
            rf.wr(toFullRegIndex(dInst.dst, getInstFields(inst).rd), fromMaybe(dataWb, maybeData));
            // always redirect
            pc <= nextPc;
            state <= IMMU;
        end
    endrule

    rule doTrap(state == Trap);
        // TODO: move this to WB
        let csrfResult <- csrf.wr(
                pc,
                tagged Invalid,
                getInstFields(inst).csr,
                0, // data
                addr,
                (exception matches tagged Valid .e ? tagged Valid (tagged Exception e) : tagged Invalid), // exception cause
                0,
                False,
                False);

        Maybe#(Addr) maybeNextPc = tagged Invalid;
        Maybe#(Data) maybeData = tagged Invalid;
        Maybe#(TrapCause) maybeTrap = tagged Invalid;
        case (csrfResult) matches
            tagged Exception .exc:
                begin
                    maybeNextPc = tagged Valid exc.trapHandlerPC;
                    maybeTrap = tagged Valid exc.exception;
                end
            tagged RedirectPC .newPc:
                maybeNextPc = tagged Valid newPc;
            tagged CsrData .data:
                maybeData = tagged Valid data;
            tagged None:
                noAction;
        endcase

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(?, maybeNextPc),
                data: fromMaybe(data, maybeData),
                addr: addr,
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        // redirection will happpen in trap2
        // by construction maybeNextPc is always valid
        nextPc <= fromMaybe(nextPc, maybeNextPc);
        state <= Trap2;
    endrule

    // There is a second trap state to ensure that the frontEndCsrs reflect the updated state of the processor
    rule doTrap2(state == Trap2);
        pc <= nextPc;
        state <= IMMU;
    endrule

    method Action start(Addr startPc);
        running <= True;
        pc <= startPc;
        state <= IMMU;
        csrState <= defaultValue;
        if (verbose) $fdisplay(fout, "[frontend] starting from pc = 0x%08x", startPc);
    endmethod
    method Action stop;
        running <= False;
        state <= Wait;
    endmethod

    method ActionValue#(VerificationPacket) getVerificationPacket;
        let verificationPacket = verificationPackets.first;
        verificationPackets.deq;
        return verificationPacket;
    endmethod

    method ActionValue#(VMInfo) updateVMInfoI;
        return csrf.vmI;
    endmethod
    method ActionValue#(VMInfo) updateVMInfoD;
        return csrf.vmD;
    endmethod

endmodule

// Copyright (c) 2016 Massachusetts Institute of Technology

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

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

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

import ClientServer::*;
import Connectable::*;
import DefaultValue::*;
import FIFO::*;
import GetPut::*;
import Vector::*;

import Abstraction::*;
import RegUtil::*;
import RVRFile::*;
import RVCsrFile::*;
import RVExec::*;
import RVFpu::*;
import RVMulDiv::*;
import RVTypes::*;
import VerificationPacket::*;

import RVAlu::*;
import RVControl::*;
import RVDecode::*;
import RVMemory::*;

// This interface is the combination of FrontEnd and BackEnd
interface Core;
    method Action start(Addr startPc);
    method Action stop;

    method ActionValue#(VerificationPacket) getVerificationPacket;
    method ActionValue#(VMInfo) updateVMInfoI;
    method ActionValue#(VMInfo) updateVMInfoD;

    interface Client#(FenceReq, FenceResp) fence;
endinterface

instance Connectable#(Core, MemorySystem);
    module mkConnection#(Core core, MemorySystem mem)(Empty);
        mkConnection(core.fence, mem.fence);
        mkConnection(toGet(core.updateVMInfoI), toPut(mem.updateVMInfoI));
        mkConnection(toGet(core.updateVMInfoD), toPut(mem.updateVMInfoD));
    endmodule
endinstance

typedef enum {
    Wait,
    IMMU,
    IF,
    Dec,
    RegRead,
    Execute,
    Mem,
    WB,
    Trap,
    Trap2
} ProcState deriving (Bits, Eq, FShow);

module mkMulticycleCore#(
        Server#(RVIMMUReq, RVIMMUResp) ivat,
        Server#(RVIMemReq, RVIMemResp) ifetch,
        Server#(RVDMMUReq, RVDMMUResp) dvat,
        Server#(RVDMemReq, RVDMemResp) dmem,
        Bool ipi,
        Bool timerInterrupt,
        Data timer,
        Bool externalInterrupt,
        Data hartID
    )
        (Core);
    let verbose = False;
    File fout = stdout;

    ArchRFile rf <- mkArchRFile;
    RVCsrFile csrf <- mkRVCsrFile(hartID, timer, timerInterrupt, ipi, externalInterrupt);
    MulDivExec mulDiv <- mkBoothRoughMulDivExec;
    FpuExec fpu <- mkFpuExecPipeline;

    Reg#(Bool) running <- mkReg(False);
    Reg#(ProcState) state <- mkReg(Wait);

    Reg#(Addr) pc <- mkReg(0);
    Reg#(Maybe#(ExceptionCause)) exception <- mkReg(tagged Invalid);
    Reg#(Instruction) inst <- mkReg(0);
    Reg#(RVDecodedInst) dInst <- mkReg(unpack(0));
    Reg#(FrontEndCsrs) csrState <- mkReadOnlyReg( FrontEndCsrs { vmI: csrf.vmI, state: csrf.csrState } );

    Reg#(Data) rVal1 <- mkReg(0);
    Reg#(Data) rVal2 <- mkReg(0);
    Reg#(Data) rVal3 <- mkReg(0);
    Reg#(Data) data <- mkReg(0);
    Reg#(Data) addr <- mkReg(0);
    Reg#(Data) nextPc <- mkReg(0);

    FIFO#(Data)         toHost <- mkFIFO1;
    FIFO#(Data)         fromHost <- mkFIFO1;

    FIFO#(VerificationPacket) verificationPackets <- mkFIFO1;

    rule doInstMMU(running && state == IMMU);
        // request address translation from MMU
        ivat.request.put(pc);
        // reset states
        inst <= unpack(0);
        dInst <= unpack(0);
        exception <= tagged Invalid;
        // go to InstFetch stage
        state <= IF;
    endrule

    rule doInstFetch(state == IF);
        // I wanted notation like this:
        // let {addr: .phyPc, exception: .exMMU} = mmuResp.first;
        let resp <- ivat.response.get;
        let phyPc = resp.addr;
        let exMMU = resp.exception;

        if (!isValid(exMMU)) begin
            // no translation exception
            ifetch.request.put(phyPc);
            // go to decode stage
            state <= Dec;
        end else begin
            // translation exception (instruction access fault)
            exception <= exMMU;
            // send instruction to backend
            state <= Trap;
        end
    endrule

    rule doDecode(state == Dec);
        let fInst <- ifetch.response.get;

        let decInst = decodeInst(fInst);

        if (decInst matches tagged Valid .validDInst) begin
            // Legal instruction
            dInst <= validDInst;
        end else begin
            // Illegal instruction
            exception <= tagged Valid IllegalInst;
        end

        inst <= fInst;
        state <= isValid(decInst) ? RegRead : Trap;
    endrule

    rule doRegRead(state == RegRead);
        rVal1 <= rf.rd1(toFullRegIndex(dInst.rs1, getInstFields(inst).rs1));
        rVal2 <= rf.rd2(toFullRegIndex(dInst.rs2, getInstFields(inst).rs2));
        rVal3 <= rf.rd3(toFullRegIndex(dInst.rs3, getInstFields(inst).rs3));
        state <= Execute;
    endrule

    rule doExecute(state == Execute);
        let dataEx = 0;
        let addrEx = 0;
        let nextPcEx = pc + 4;

        Maybe#(Data) imm = getImmediate(dInst.imm, dInst.inst);
        case (dInst.execFunc) matches
            tagged Alu    .aluInst:
                begin
                    dataEx = execAluInst(aluInst, rVal1, rVal2, imm, pc);
                end
            tagged Br     .brFunc:
                begin
                    // data for jal
                    dataEx = pc + 4;
                    nextPcEx = execControl(brFunc, rVal1, rVal2, imm, pc);
                end
            tagged Mem    .memInst:
                begin
                    // data for store and AMO
                    dataEx = rVal2;
                    addrEx = addrCalc(rVal1, imm);
                    dvat.request.put(RVDMMUReq {addr: addrEx, size: memInst.size, op: (memInst.op matches tagged Mem .memOp ? memOp : St)});
                end
            tagged MulDiv .mulDivInst: mulDiv.exec(mulDivInst, rVal1, rVal2);
            tagged Fence  .fenceInst:  noAction;
            // TODO: Handle dynamic rounding mode
            tagged Fpu    .fpuInst:    fpu.exec(fpuInst, getInstFields(inst).rm, rVal1, rVal2, rVal3);
            tagged System .systemInst:
                begin
                    // data for CSR instructions
                    dataEx = fromMaybe(rVal1, imm);
                end
        endcase

        data <= dataEx;
        addr <= addrEx;
        nextPc <= nextPcEx;

        state <= dInst.execFunc matches tagged Mem .* ? Mem : WB;
    endrule

    rule doMem(state == Mem);
        let resp <- dvat.response.get;
        let pAddr = resp.addr;
        let exMMU = resp.exception;

        // TODO: make this type safe! get rid of .Mem accesses to tagged union
        if (!isValid(exMMU)) begin
            dmem.request.put( RVDMemReq {
                    op: dInst.execFunc.Mem.op,
                    size: dInst.execFunc.Mem.size,
                    isUnsigned: dInst.execFunc.Mem.isUnsigned,
                    addr: pAddr,
                    data: data } );
            state <= WB;
        end else begin
            exception <= exMMU;
            state <= Trap;
        end
    endrule

    rule doWB(state == WB);
        let dataWb = data;
        let addrWb = addr;
        let nextPcWb = nextPc;
        let fflagsWb = 0;
        let exceptionWB = exception;

        case(dInst.execFunc) matches
            tagged MulDiv .*: begin
                    dataWb = mulDiv.result_data();
                    mulDiv.result_deq;
                end
            tagged Fpu .*: begin
                    let fpuResult = toFullResult(fpu.result_data);
                    dataWb = fpuResult.data;
                    fflagsWb = fpuResult.fflags;
                    fpu.result_deq;
                end
            tagged Mem .memInst:
                begin
                    if (getsResponse(memInst.op)) begin
                        dataWb <- dmem.response.get;
                    end
                end
        endcase

        Maybe#(TrapCause) trap = tagged Invalid;
        if (exceptionWB matches tagged Valid .validException) begin
            trap = tagged Valid (tagged Exception validException);
        end else if ((nextPcWb & 'b011) != 0) begin
            trap = tagged Valid (tagged Exception InstAddrMisaligned);
        end

        if (dInst.execFunc matches tagged Mem .*) begin
            // don't bother checking for interrupts since you just did a memory operation
        end else begin
            // check for interrupts (this overwrites current exceptions)
            if (csrf.readyInterrupt matches tagged Valid .validInterrupt) begin
                trap = tagged Valid (tagged Interrupt validInterrupt);
            end
        end
        Bool checkForInterrupts = dInst.execFunc matches tagged Mem .* ? False : True;
        Bool extensionDirty = False;
        Bool fpuDirty = (dInst.dst == tagged Valid Fpu);
        let csrfResult <- csrf.wr(
                pc,
                // performing system instructions
                dInst.execFunc matches tagged System .sysInst ? tagged Valid sysInst : tagged Invalid,
                getInstFields(inst).csr,
                dataWb, // either rf[rs1] or zimm, computed in basicExec
                addrWb,
                // handling exceptions
                trap,
                // indirect writes
                fflagsWb,
                fpuDirty,
                extensionDirty);

        Maybe#(Addr) maybeNextPc = tagged Invalid;
        Maybe#(Data) maybeData = tagged Invalid;
        Maybe#(TrapCause) maybeTrap = tagged Invalid;
        case (csrfResult) matches
            tagged Exception .exc:
                begin
                    maybeNextPc = tagged Valid exc.trapHandlerPC;
                    maybeTrap = tagged Valid exc.exception;
                end
            tagged RedirectPC .newPc:
                maybeNextPc = tagged Valid newPc;
            tagged CsrData .data:
                maybeData = tagged Valid data;
            tagged None:
                noAction;
        endcase

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(nextPcWb, maybeNextPc),
                data: fromMaybe(dataWb, maybeData),
                addr: addr,
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        if (maybeNextPc matches tagged Valid .replayPc) begin
            // This instruction didn't retire

            // redirect happens in Trap2
            nextPc <= replayPc;
            state <= Trap2;
        end else begin
            // This instruction retired
            // write to the register file
            rf.wr(toFullRegIndex(dInst.dst, getInstFields(inst).rd), fromMaybe(dataWb, maybeData));
            // always redirect
            pc <= nextPc;
            state <= IMMU;
        end
    endrule

    rule doTrap(state == Trap);
        // TODO: move this to WB
        let csrfResult <- csrf.wr(
                pc,
                tagged Invalid,
                getInstFields(inst).csr,
                0, // data
                addr,
                (exception matches tagged Valid .e ? tagged Valid (tagged Exception e) : tagged Invalid), // exception cause
                0,
                False,
                False);

        Maybe#(Addr) maybeNextPc = tagged Invalid;
        Maybe#(Data) maybeData = tagged Invalid;
        Maybe#(TrapCause) maybeTrap = tagged Invalid;
        case (csrfResult) matches
            tagged Exception .exc:
                begin
                    maybeNextPc = tagged Valid exc.trapHandlerPC;
                    maybeTrap = tagged Valid exc.exception;
                end
            tagged RedirectPC .newPc:
                maybeNextPc = tagged Valid newPc;
            tagged CsrData .data:
                maybeData = tagged Valid data;
            tagged None:
                noAction;
        endcase

        // send verification packet
        verificationPackets.enq( VerificationPacket {
                skippedPackets: 0,
                pc: pc,
                nextPc: fromMaybe(?, maybeNextPc),
                data: fromMaybe(data, maybeData),
                addr: addr,
                instruction: inst,
                dst: {pack(dInst.dst), getInstFields(inst).rd},
                trap: isValid(maybeTrap),
                trapType: (case (fromMaybe(unpack(0), maybeTrap)) matches
                        tagged Exception .x: (zeroExtend(pack(x)));
                        tagged Interrupt .x: (zeroExtend(pack(x)) | 8'h80);
                    endcase) });

        // redirection will happpen in trap2
        // by construction maybeNextPc is always valid
        nextPc <= fromMaybe(nextPc, maybeNextPc);
        state <= Trap2;
    endrule

    // There is a second trap state to ensure that the frontEndCsrs reflect the updated state of the processor
    rule doTrap2(state == Trap2);
        pc <= nextPc;
        state <= IMMU;
    endrule

    method Action start(Addr startPc);
        running <= True;
        pc <= startPc;
        state <= IMMU;
        csrState <= defaultValue;
        if (verbose) $fdisplay(fout, "[frontend] starting from pc = 0x%08x", startPc);
    endmethod
    method Action stop;
        running <= False;
        state <= Wait;
    endmethod

    method ActionValue#(VerificationPacket) getVerificationPacket;
        let verificationPacket = verificationPackets.first;
        verificationPackets.deq;
        return verificationPacket;
    endmethod

    method ActionValue#(VMInfo) updateVMInfoI;
        return csrf.vmI;
    endmethod
    method ActionValue#(VMInfo) updateVMInfoD;
        return csrf.vmD;
    endmethod

endmodule


Implemented all user instructions we plan to implement.

import FShow::*;

typedef Bit#( 5) Ridx;  // Register index
typedef Bit#(16) Immd;  // Immediate
typedef Bit#( 5) Sham;  // Shift ammount
typedef Bit#(16) Joff;  // Jump offset
typedef Bit#(26) Jtgt;  // Jump target
typedef Bit#(16) Moff;  // Memory offset

typedef union tagged {
    // Arithmetic Operations
    struct { Ridx rs; Ridx rt; Ridx rd; } ADD;
    struct { Ridx rs; Ridx rt; Immd im; } ADDI;
    struct { Ridx rs; Ridx rt; Immd im; } ADDIU;
    struct { Ridx rs; Ridx rt; Ridx rd; } ADDU;
    struct {          Ridx rt; Immd im; } LUI;
    struct { Ridx rs; Ridx rt; Ridx rd; } SUB;
    struct { Ridx rs; Ridx rt; Ridx rd; } SUBU;

    // Shift and Rotate Operations
    struct { Ridx rt; Ridx rd; Sham sa; } SLL;
    struct { Ridx rs; Ridx rt; Ridx rd; } SLLV;
    struct { Ridx rt; Ridx rd; Sham sa; } SRA;
    struct { Ridx rs; Ridx rt; Ridx rd; } SRAV;
    struct { Ridx rt; Ridx rd; Sham sa; } SRL;
    struct { Ridx rs; Ridx rt; Ridx rd; } SRLV;

    // Logical and Bit-Field Operations
    struct { Ridx rs; Ridx rt; Ridx rd; } AND;
    struct { Ridx rs; Ridx rt; Immd im; } ANDI;
    struct { Ridx rs; Ridx rt; Ridx rd; } NOR;
    struct { Ridx rs; Ridx rt; Ridx rd; } OR;
    struct { Ridx rs; Ridx rt; Immd im; } ORI;
    struct { Ridx rs; Ridx rt; Ridx rd; } XOR;
    struct { Ridx rs; Ridx rt; Immd im; } XORI;

    // Condition Testing and Conditional Move Operations
    struct { Ridx rd; Ridx rs; Ridx rt; } SLT;
    struct { Ridx rs; Ridx rt; Immd im; } SLTI;
    struct { Ridx rs; Ridx rt; Immd im; } SLTIU;
    struct { Ridx rs; Ridx rt; Ridx rd; } SLTU;

    // Multiply and divide operations
    struct { Ridx rs; Ridx rt;          } DIV;
    struct { Ridx rs; Ridx rt;          } DIVU;
    struct { Ridx rs; Ridx rt;          } MULT;
    struct { Ridx rs; Ridx rt;          } MULTU;

    // Accumulator Access Operations
    struct {                   Ridx rd; } MFHI;
    struct {                   Ridx rd; } MFLO;

    // Jumps and Branches
    struct { Ridx rs; Ridx rt; Joff of; } BEQ;
    struct { Ridx rs;          Joff of; } BGEZ;
    struct { Ridx rs;          Joff of; } BGTZ;
    struct { Ridx rs;          Joff of; } BLEZ;
    struct { Ridx rs;          Joff of; } BLTZ;
    struct { Ridx rs; Ridx rt; Joff of; } BNE;
    struct {                   Jtgt tg; } J;
    struct {                   Jtgt tg; } JAL;
    struct { Ridx rs;          Ridx rd; } JALR;
    struct { Ridx rs;                   } JR;

    // Load and Store Operations
    struct { Ridx rb; Ridx rt; Moff of; } LB;
    struct { Ridx rb; Ridx rt; Moff of; } LBU;
    struct { Ridx rb; Ridx rt; Moff of; } LH;
    struct { Ridx rb; Ridx rt; Moff of; } LHU;
    struct { Ridx rb; Ridx rt; Moff of; } LW;
    struct { Ridx rb; Ridx rt; Moff of; } SB;
    struct { Ridx rb; Ridx rt; Moff of; } SH;
    struct { Ridx rb; Ridx rt; Moff of; } SW;

    void ILLEGAL;
} Instr deriving(Eq);

typedef Bit#(6) Opcode;

Opcode opSPECIAL = 6'b000000;

typedef Bit#(6) SpecOp;

SpecOp soADD     = 6'b100000;
SpecOp soADDU    = 6'b100001;
SpecOp soSUB     = 6'b100010;
SpecOp soSUBU    = 6'b100011;
SpecOp soSLL     = 6'b000000;
SpecOp soSLLV    = 6'b000100;
SpecOp soSRA     = 6'b000011;
SpecOp soSRAV    = 6'b000111;
SpecOp soSRL     = 6'b000010;
SpecOp soSRLV    = 6'b000110;
SpecOp soAND     = 6'b100100;
SpecOp soNOR     = 6'b100111;
SpecOp soOR      = 6'b100101;
SpecOp soXOR     = 6'b100110;
SpecOp soSLT     = 6'b101010;
SpecOp soSLTU    = 6'b101011;
SpecOp soDIV     = 6'b011010;
SpecOp soDIVU    = 6'b011011;
SpecOp soMULT    = 6'b011000;
SpecOp soMULTU   = 6'b011001;
SpecOp soMFHI    = 6'b010000;
SpecOp soMFLO    = 6'b010010;
SpecOp soJALR    = 6'b001001;
SpecOp soJR      = 6'b001000;

Opcode opADDI    = 6'b001000;
Opcode opADDIU   = 6'b001001;
Opcode opLUI     = 6'b001111;
Opcode opANDI    = 6'b001100;
Opcode opORI     = 6'b001101;
Opcode opXORI    = 6'b001110;
Opcode opSLTI    = 6'b001010;
Opcode opSLTIU   = 6'b001011;
Opcode opBEQ     = 6'b000100;

Opcode opREGIMM  = 6'b000001;

typedef Bit#(5) RImmOp;

RImmOp roBGEZ    = 5'b00001;
RImmOp roBLTZ    = 5'b00000;

Opcode opBGTZ    = 6'b000111;
Opcode opBLEZ    = 6'b000110;
Opcode opBNE     = 6'b000101;
Opcode opJ       = 6'b000010;
Opcode opJAL     = 6'b000011;
Opcode opLB      = 6'b100000;
Opcode opLBU     = 6'b100100;
Opcode opLH      = 6'b100001;
Opcode opLHU     = 6'b100101;
Opcode opLW      = 6'b100011;
Opcode opSB      = 6'b101000;
Opcode opSH      = 6'b101001;
Opcode opSW      = 6'b101011;

instance Bits#(Instr, 32);

    function Bit#(32) pack(Instr instr);
        case (instr) matches
            tagged ADD   .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soADD   };
            tagged ADDI  .s: return { opADDI,    s.rs, s.rt, s.im                };
            tagged ADDIU .s: return { opADDIU,   s.rs, s.rt, s.im                };
            tagged ADDU  .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soADDU  };
            tagged LUI   .s: return { opLUI,     5'b0, s.rt, s.im                };
            tagged SUB   .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSUB   };
            tagged SUBU  .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSUBU  };
            tagged SLL   .s: return { opSPECIAL, 5'b0, s.rt, s.rd, s.sa, soSLL   };
            tagged SLLV  .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSLLV  };
            tagged SRA   .s: return { opSPECIAL, 5'b0, s.rt, s.rd, s.sa, soSRA   };
            tagged SRAV  .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSRAV  };
            tagged SRL   .s: return { opSPECIAL, 5'b0, s.rt, s.rd, s.sa, soSRL   };
            tagged SRLV  .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSRLV  };
            tagged AND   .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soAND   };
            tagged ANDI  .s: return { opANDI,    s.rs, s.rt, s.im                };
            tagged NOR   .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soNOR   };
            tagged OR    .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soOR    };
            tagged ORI   .s: return { opORI,     s.rs, s.rt, s.im                };
            tagged XOR   .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soXOR   };
            tagged XORI  .s: return { opXORI,    s.rs, s.rt, s.im                };
            tagged SLT   .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSLT   };
            tagged SLTI  .s: return { opSLTI,    s.rs, s.rt, s.im                };
            tagged SLTIU .s: return { opSLTIU,   s.rs, s.rt, s.im                };
            tagged SLTU  .s: return { opSPECIAL, s.rs, s.rt, s.rd, 5'b0, soSLTU  };
            tagged DIV   .s: return { opSPECIAL, s.rs, s.rt,      10'b0, soDIV   };
            tagged DIVU  .s: return { opSPECIAL, s.rs, s.rt,      10'b0, soDIVU  };
            tagged MULT  .s: return { opSPECIAL, s.rs, s.rt,      10'b0, soMULT  };
            tagged MULTU .s: return { opSPECIAL, s.rs, s.rt,      10'b0, soMULTU };
            tagged MFHI  .s: return { opSPECIAL,10'b0, s.rd,       5'b0, soMFHI  };
            tagged MFLO  .s: return { opSPECIAL,10'b0, s.rd,       5'b0, soMFLO  };
            tagged BEQ   .s: return { opBEQ,     s.rs, s.rt,       s.of          };
            tagged BGEZ  .s: return { opREGIMM,  s.rs, roBGEZ,     s.of          };
            tagged BGTZ  .s: return { opBGTZ,    s.rs, 5'b0,       s.of          };
            tagged BLEZ  .s: return { opBLEZ,    s.rs, 5'b0,       s.of          };
            tagged BLTZ  .s: return { opREGIMM,  s.rs, roBLTZ,     s.of          };
            tagged BNE   .s: return { opBNE,     s.rs, s.rt,       s.of          };
            tagged J     .s: return { opJ,       s.tg                            };
            tagged JAL   .s: return { opJAL,     s.tg                            };
            tagged JALR  .s: return { opSPECIAL, s.rs, 5'b0, s.rd, 5'b0, soJALR  };
            tagged JR    .s: return { opSPECIAL, s.rs,            15'b0, soJR    };
            tagged LB    .s: return { opLB,      s.rb, s.rt, s.of                };
            tagged LBU   .s: return { opLBU,     s.rb, s.rt, s.of                };
            tagged LH    .s: return { opLH,      s.rb, s.rt, s.of                };
            tagged LHU   .s: return { opLHU,     s.rb, s.rt, s.of                };
            tagged LW    .s: return { opLW,      s.rb, s.rt, s.of                };
            tagged SB    .s: return { opSB,      s.rb, s.rt, s.of                };
            tagged SH    .s: return { opSB,      s.rb, s.rt, s.of                };
            tagged SW    .s: return { opSW,      s.rb, s.rt, s.of                };
            tagged ILLEGAL : return 0;
        endcase
    endfunction

    function Instr unpack(Bit#(32) instr);
        let op = instr[31:26];
        let rs = instr[25:21];
        let rt = instr[20:16];
        let rd = instr[15:11];
        let sa = instr[10: 6];
        let so = instr[ 5: 0];
        let im = instr[15: 0];
        let tg = instr[25: 0];
        let ro = instr[20:16];
        let of = instr[15: 0];
        let rb = instr[25:21];

        case(op)
            opSPECIAL:
                case(so)
                    soADD:   return ADD   {rs:rs, rt:rt, rd:rd};
                    soADDU:  return ADDU  {rs:rs, rt:rt, rd:rd};
                    soSUB:   return SUB   {rs:rs, rt:rt, rd:rd};
                    soSUBU:  return SUBU  {rs:rs, rt:rt, rd:rd};
                    soSLL:   return SLL   {rt:rt, rd:rd, sa:sa};
                    soSLLV:  return SLLV  {rs:rs, rt:rt, rd:rd};
                    soSRA:   return SRA   {rt:rt, rd:rd, sa:sa};
                    soSRAV:  return SRAV  {rs:rs, rt:rt, rd:rd};
                    soSRL:   return SRL   {rt:rt, rd:rd, sa:sa};
                    soSRLV:  return SRLV  {rs:rs, rt:rt, rd:rd};
                    soAND:   return AND   {rs:rs, rt:rt, rd:rd};
                    soNOR:   return NOR   {rs:rs, rt:rt, rd:rd};
                    soOR:    return OR    {rs:rs, rt:rt, rd:rd};
                    soXOR:   return XOR   {rs:rs, rt:rt, rd:rd};
                    soSLT:   return SLT   {rs:rs, rt:rt, rd:rd};
                    soSLTU:  return SLTU  {rs:rs, rt:rt, rd:rd};
                    soDIV:   return DIV   {rs:rs, rt:rt       };
                    soDIVU:  return DIVU  {rs:rs, rt:rt       };
                    soMULT:  return MULT  {rs:rs, rt:rt       };
                    soMULTU: return MULTU {rs:rs, rt:rt       };
                    soMFHI:  return MFHI  {rd:rd              };
                    soMFLO:  return MFLO  {rd:rd              };
                    soJALR:  return JALR  {rs:rs, rd:rd       };
                    soJR:    return JR    {rs:rs              };
                endcase
            opADDI:  return ADDI  { rs:rs, rt:rt, im:im };
            opADDIU: return ADDIU { rs:rs, rt:rt, im:im };
            opLUI:   return LUI   { rt:rt, im:im        };
            opANDI:  return ANDI  { rs:rs, rt:rt, im:im };
            opORI:   return ORI   { rs:rs, rt:rt, im:im };
            opXORI:  return XORI  { rs:rs, rt:rt, im:im };
            opSLTI:  return SLTI  { rs:rs, rt:rt, im:im };
            opSLTIU: return SLTIU { rs:rs, rt:rt, im:im };
            opBEQ:   return BEQ   { rs:rs, rt:rt, of:of };
            opREGIMM:
                case(ro)
                    roBGEZ: return BGEZ { rs:rs, of:of  };
                    roBLTZ: return BLTZ { rs:rs, of:of  };
                endcase
            opBGTZ:  return BGTZ  { rs:rs, of:of        };
            opBLEZ:  return BLEZ  { rs:rs, of:of        };
            opBNE:   return BNE   { rs:rs, rt:rt, of:of };
            opJ:     return J     { tg:tg               };
            opJAL:   return JAL   { tg:tg               };
            opLB:    return LB    { rb:rb, rt:rt, of:of };
            opLBU:   return LBU   { rb:rb, rt:rt, of:of };
            opLH:    return LH    { rb:rb, rt:rt, of:of };
            opLHU:   return LHU   { rb:rb, rt:rt, of:of };
            opLW:    return LW    { rb:rb, rt:rt, of:of };
            opSB:    return SB    { rb:rb, rt:rt, of:of };
            opSH:    return SH    { rb:rb, rt:rt, of:of };
            opSW:    return SW    { rb:rb, rt:rt, of:of };
            default: return ILLEGAL;
        endcase
    endfunction

endinstance

instance FShow#(Instr);
    function Fmt fshow(Instr instr);
        case (instr) matches
            tagged ADD   .s: return $format("add r%0d, r%0d, r%0d",   s.rd, s.rs, s.rt);
            tagged ADDI  .s: return $format("addi r%0d, r%0d, 0x%x",  s.rt, s.rs, s.im);
            tagged ADDIU .s: return $format("addiu r%0d, r%0d, 0x%x", s.rt, s.rs, s.im);
            tagged ADDU  .s: return $format("addu r%0d, r%0d, r%0d",  s.rd, s.rs, s.rt);
            tagged LUI   .s: return $format("lui r%0d, 0x%x",         s.rt, s.im      );
            tagged SUB   .s: return $format("sub r%0d, r%0d, r%0d",   s.rd, s.rs, s.rt);
            tagged SUBU  .s: return $format("subu r%0d, r%0d, r%0d",  s.rd, s.rs, s.rt);
            tagged SLL   .s: return $format("sll r%0d, r%0d, %0d",    s.rd, s.rt, s.sa);
            tagged SLLV  .s: return $format("sllv r%0d, r%0d, r%0d",  s.rd, s.rt, s.rs);
            tagged SRA   .s: return $format("sra r%0d, r%0d, %0d",    s.rd, s.rt, s.sa);
            tagged SRAV  .s: return $format("srav r%0d, r%0d, r%0d",  s.rd, s.rt, s.rs);
            tagged SRL   .s: return $format("srl r%0d, r%0d, %0d",    s.rd, s.rt, s.sa);
            tagged SRLV  .s: return $format("srlv r%0d, r%0d, r%0d",  s.rd, s.rt, s.rs);
            tagged AND   .s: return $format("and r%0d, r%0d, r%0d",   s.rd, s.rs, s.rt);
            tagged ANDI  .s: return $format("andi r%0d, r%0d, 0x%x",  s.rt, s.rs, s.im);
            tagged NOR   .s: return $format("nor r%0d, r%0d, r%0d",   s.rd, s.rs, s.rt);
            tagged OR    .s: return $format("or r%0d, r%0d, r%0d",    s.rd, s.rs, s.rt);
            tagged ORI   .s: return $format("ori r%0d, r%0d, 0x%x",   s.rt, s.rs, s.im);
            tagged XOR   .s: return $format("xor r%0d, r%0d, r%0d",   s.rd, s.rs, s.rt);
            tagged XORI  .s: return $format("xori r%0d, r%0d, 0x%x",  s.rt, s.rs, s.im);
            tagged SLT   .s: return $format("slt r%0d, r%0d, r%0d",   s.rd, s.rs, s.rt);
            tagged SLTI  .s: return $format("slti r%0d, r%0d, 0x%x",  s.rt, s.rs, s.im);
            tagged SLTIU .s: return $format("sltiu r%0d, r%0d, 0x%x", s.rt, s.rs, s.im);
            tagged SLTU  .s: return $format("sltu r%0d, r%0d, r%0d",  s.rd, s.rs, s.rt);
            tagged DIV   .s: return $format("div r%0d, r%0d",         s.rs, s.rt      );
            tagged DIVU  .s: return $format("divu r%0d, r%0d",        s.rs, s.rt      );
            tagged MULT  .s: return $format("mult r%0d, r%0d",        s.rs, s.rt      );
            tagged MULTU .s: return $format("multu r%0d, r%0d",       s.rs, s.rt      );
            tagged MFHI  .s: return $format("mfhi r%0d",              s.rd            );
            tagged MFLO  .s: return $format("mflo r%0d",              s.rd            );
            tagged BEQ   .s: return $format("beq r%0d, r%0d, 0x%x",   s.rs, s.rt, s.of);
            tagged BGEZ  .s: return $format("bgez r%0d, 0x%x",        s.rs, s.of      );
            tagged BGTZ  .s: return $format("bgtz r%0d, 0x%x",        s.rs, s.of      );
            tagged BLEZ  .s: return $format("blez r%0d, 0x%x",        s.rs, s.of      );
            tagged BLTZ  .s: return $format("bltz r%0d, 0x%x",        s.rs, s.of      );
            tagged BNE   .s: return $format("bne r%0d, r%0d, 0x%x",   s.rs, s.rt, s.of);
            tagged J     .s: return $format("j 0x%x",                 s.tg            );
            tagged JAL   .s: return $format("jal 0x%x",               s.tg            );
            tagged JALR  .s: return $format("jalr r%0d, r%0d",        s.rd, s.rs      );
            tagged JR    .s: return $format("jr r%0d",                s.rs            );
            tagged LB    .s: return $format("lb r%0d, 0x%x(r%0d)",    s.rt, s.of, s.rb);
            tagged LBU   .s: return $format("lbu r%0d, 0x%x(r%0d)",   s.rt, s.of, s.rb);
            tagged LH    .s: return $format("lh r%0d, 0x%x(r%0d)",    s.rt, s.of, s.rb);
            tagged LHU   .s: return $format("lhu r%0d, 0x%x(r%0d)",   s.rt, s.of, s.rb);
            tagged LW    .s: return $format("lw r%0d, 0x%x(r%0d)",    s.rt, s.of, s.rb);
            tagged SB    .s: return $format("sb r%0d, 0x%x(r%0d)",    s.rt, s.of, s.rb);
            tagged SH    .s: return $format("sh r%0d, 0x%x(r%0d)",    s.rt, s.of, s.rb);
            tagged SW    .s: return $format("sw r%0d, 0x%x(r%0d)",    s.rt, s.of, s.rb);
            tagged ILLEGAL : return $format("illegal instruction");
        endcase
    endfunction
endinstance

import FShow::*;

typedef  Bit#( 5) Ridx;  // Register index
typedef UInt#(16) Uimm;  // Unsigned immediate
typedef  Int#(16) Simm;  // Signed immediate
typedef  Bit#( 5) Sham;  // Shift ammount
typedef  Bit#(16) Joff;  // Jump offset
typedef  Bit#(26) Jtgt;  // Jump target
typedef  Bit#(16) Moff;  // Memory offset

typedef union tagged {
    // Arithmetic Operations
    struct { Ridx rs; Ridx rt; Ridx rd; } ADD;
    struct { Ridx rs; Ridx rt; Simm im; } ADDI;
    struct { Ridx rs; Ridx rt; Simm im; } ADDIU;
    struct { Ridx rs; Ridx rt; Ridx rd; } ADDU;
    struct {          Ridx rt; Uimm im; } LUI;
    struct { Ridx rs; Ridx rt; Ridx rd; } SUB;
    struct { Ridx rs; Ridx rt; Ridx rd; } SUBU;

    // Shift and Rotate Operations
    struct { Ridx rt; Ridx rd; Sham sa; } SLL;
    struct { Ridx rs; Ridx rt; Ridx rd; } SLLV;
    struct { Ridx rt; Ridx rd; Sham sa; } SRA;
    struct { Ridx rs; Ridx rt; Ridx rd; } SRAV;
    struct { Ridx rt; Ridx rd; Sham sa; } SRL;
    struct { Ridx rs; Ridx rt; Ridx rd; } SRLV;

    // Logical and Bit-Field Operations
    struct { Ridx rs; Ridx rt; Ridx rd; } AND;
    struct { Ridx rs; Ridx rt; Uimm im; } ANDI;
    struct { Ridx rs; Ridx rt; Ridx rd; } NOR;
    struct { Ridx rs; Ridx rt; Ridx rd; } OR;
    struct { Ridx rs; Ridx rt; Uimm im; } ORI;
    struct { Ridx rs; Ridx rt; Ridx rd; } XOR;
    struct { Ridx rs; Ridx rt; Uimm im; } XORI;

    // Condition Testing and Conditional Move Operations
    struct { Ridx rd; Ridx rs; Ridx rt; } SLT;
    struct { Ridx rs; Ridx rt; Simm im; } SLTI;
    struct { Ridx rd; Ridx rs; Ridx rt; } SLTIU;
    struct { Ridx rd; Ridx rt; Uimm im; } SLTU;

    // Multiply and divide operations
    struct { Ridx rs; Ridx rt;          } DIV;
    struct { Ridx rs; Ridx rt;          } DIVU;
    struct { Ridx rs; Ridx rt;          } MULT;
    struct { Ridx rs; Ridx rt;          } MULTU;

    // Accumulator Access Operations
    struct {                   Ridx rd; } MFHI;
    struct {                   Ridx rd; } MFLO;

    // Jumps and Branches
    struct { Ridx rs; Ridx rt; Joff of; } BEQ;
    struct { Ridx rs;          Joff of; } BGEZ;
    struct { Ridx rs;          Joff of; } BGTZ;
    struct { Ridx rs;          Joff of; } BLEZ;
    struct { Ridx rs;          Joff of; } BLTZ;
    struct { Ridx rs; Ridx rt; Joff of; } BNE;
    struct {                   Jtgt tg; } J;
    struct {                   Jtgt tg; } JAL;
    struct { Ridx rs;          Ridx rd; } JALR;
    struct { Ridx rs;                   } JR;

    // Load and Store Operations
    struct { Ridx rb; Ridx rt; Moff of; } LB;
    struct { Ridx rb; Ridx rt; Moff of; } LBU;
    struct { Ridx rb; Ridx rt; Moff of; } LH;
    struct { Ridx rb; Ridx rt; Moff of; } LHU;
    struct { Ridx rb; Ridx rt; Moff of; } LW;
    struct { Ridx rb; Ridx rt; Moff of; } SB;
    struct { Ridx rb; Ridx rt; Moff of; } SH;
    struct { Ridx rb; Ridx rt; Moff of; } SW;

    void ILLEGAL;
} Instr deriving(Eq);

typedef Bit#(6) Opcode;


added flash state machine

added flash state machine

import Vector::*;
import Clocks::*;
import Connectable::*;
import GetPut::*;
import FIFOF::*;
import BRAM::*;
import Probe::*;
import StmtFSM::*;
import TriState::*;
import Vector::*;
import ConnectalXilinxCells::*;

`ifdef SIMULATION
import I28F512P33::*;
`endif

// interface to BPI Flash (PC28F00AG18FE)

(* always_ready, always_enabled *)
interface BpiFlashPins;
   interface Clock deleteme_unused_clock;
//   interface Reset rst;
   interface Vector#(16,Inout#(Bit#(1))) data;
   method Bit#(25) addr();
   method Bit#(1) adv_b();
   method Bit#(1) ce_b();
   method Bit#(1) oe_b();
   method Bit#(1) we_b();
`ifdef BPI_HAS_WP
   method Bit#(1) wp_b();
`endif
`ifdef BPI_HAS_VPP
   method Bit#(1) vpp();
`endif
   method Action wait_in(Bit#(1) b);
endinterface

interface BpiPins;
   interface BpiFlashPins flash;
endinterface

interface BpiFlash;
   interface BpiFlashPins flash;
   method Action setParameters(Bit#(16) cycles, Bool stallOnWaitIn);
   interface Server#(BRAMRequest#(Bit#(25),Bit#(16)),Bit#(16)) server;
endinterface

module mkBpiFlash(BpiFlash);
   let clock <- exposeCurrentClock();
   let reset <- exposeCurrentReset();

   Reg#(Bit#(1)) rst_o <- mkReg(0);
   Reg#(Bit#(1)) ce <- mkReg(1);
   Reg#(Bit#(1)) we <- mkReg(1);
   Reg#(Bit#(1)) oe <- mkReg(1);
   Reg#(Bit#(1)) adv <- mkReg(1);
   Reg#(Bit#(16)) data_o <- mkReg(0);
   Reg#(Bit#(25)) addr_o <- mkReg(0);
   Reg#(Bit#(16)) delayReg <- mkReg(10);
   Reg#(Bool)     stallOnWaitReg  <- mkReg(False);
   Reg#(BRAMRequest#(Bit#(25),Bit#(16))) reqReg <- mkReg(unpack(0));
   FIFOF#(BRAMRequest#(Bit#(25),Bit#(16))) reqFifo <- mkFIFOF();
   FIFOF#(Bit#(16)) dataFifo <- mkFIFOF();

`ifndef SIMULATION
   Wire#(Bit#(1)) wait_in_b <- mkDWire(0);
   module mkDataIobuf#(Integer i)(IOBUF);
      (* hide *)
      let iobuf <- mkIOBUF(we, data_o[i]);
      return iobuf;
   endmodule
   function Inout#(Bit#(1)) iobuf_io(IOBUF iobuf); return iobuf.io; endfunction
   function Bit#(1) iobuf_o(IOBUF iobuf); return iobuf.o; endfunction
   Vector#(16, IOBUF) iobuf <- genWithM(mkDataIobuf);
   let dataIn = pack(map(iobuf_o, iobuf));
`endif

`ifdef SIMULATION
   let flash <- mkI28f512p33Load("flash.hex");
   let dataTristate <- mkTriState(oe == 1, data_o);
   mkConnection(dataTristate.io, flash.dq);
   let wait_in_b = flash.waitout();
   let dataIn = dataTristate;
   rule rl_flash_inputs;
      flash.addr(addr_o);
      flash.advneg(adv);
      flash.ceneg(ce);
      flash.oeneg(oe);
      flash.weneg(we);
      flash.wpneg(1);
      flash.vpp(0);
   endrule
`endif

   Reg#(Bit#(10)) i <- mkReg(0);

   let readFsm <- mkAutoFSM(seq
			while (True) seq
			   action

			      reqFifo.deq();
			      let req = reqFifo.first();
			      reqReg <= req;
			      addr_o <= req.address >> 1;
			      data_o <= req.datain;
			      adv <= 0;
			      ce <= 0;
			   endaction
			   delay(delayReg);
			   adv <= 1;
			   delay(delayReg);
			   action
			      if (reqReg.write)
				 we <= 0;
			      else
				 oe <= 0;
			   endaction
			   delay(delayReg);
      $display("addr_o=%x\n", addr_o);
      $display("wait_in_b=%d dataIn=%x", wait_in_b, dataIn);
			   if (reqReg.write)
			      we <= 1;
			   if (!reqReg.write && stallOnWaitReg) await (wait_in_b == 1);
      $display("wait_in_b=%d dataIn=%x", wait_in_b, dataIn);
			   if (!reqReg.write || reqReg.responseOnWrite)
			      dataFifo.enq(dataIn);
			   delay(delayReg);
			   ce <= 1;
			   oe <= 1;
			   delay(delayReg);
			   endseq
			endseq);

   method Action setParameters(Bit#(16) cycles, Bool stallOnWaitIn);
      delayReg <= cycles;
      stallOnWaitReg <= stallOnWaitIn;
   endmethod
   interface Server server;
      interface request = toPut(reqFifo);
      interface response = toGet(dataFifo);
   endinterface
`ifndef SIMULATION
   interface BpiFlashPins flash;
      interface deleteme_unused_clock = clock;
//          interface rst = defaultReset;
      interface data = map(iobuf_io, iobuf);
      method Bit#(25) addr = addr_o;
      method Bit#(1) adv_b = adv;
      method Bit#(1) ce_b = ce;
      method Bit#(1) oe_b = oe;
      method Bit#(1) we_b = we;
`ifdef BPI_HAS_WP
      method Bit#(1) wp_b = 1;
`endif
`ifdef BPI_HAS_VPP
      method Bit#(1) vpp = 0;
`endif
      method Action wait_in(Bit#(1) b);
	 wait_in_b <= b;
      endmethod
   endinterface
`endif
endmodule

import Vector::*;
import Clocks::*;

// interface to BPI Flash (PC28F00AG18FE)

(* always_ready, always_enabled *)
interface BpiFlashPins;
   interface Clock deleteme_unused_clock;
//   interface Reset rst;
   interface Vector#(16,Inout#(Bit#(1))) data;
   method Bit#(25) addr();
   method Bit#(1) adv_b();
   method Bit#(1) ce_b();
   method Bit#(1) oe_b();
   method Bit#(1) we_b();
`ifdef BPI_HAS_WP
   method Bit#(1) wp_b();
`endif
`ifdef BPI_HAS_VPP
   method Bit#(1) vpp();
`endif
   method Action wait_in(Bit#(1) b);
endinterface

interface BpiPins;
   interface BpiFlashPins flash;
endinterface