added Types.bsv with simpler input for match/action

// Copyright (c) 2015 Cornell University.

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

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

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

/* DO NOT MODIFY, AUTO GENERATED BY P4 COMPILER */

typedef struct {
   Bit#(48) dstAddr;
   Bit#(48) srcAddr;
   Bit#(16) etherType;
} HeaderType_ethernet deriving(Bits, Eq);
instance DefaultValue#(HeaderType_ethernet);
   defaultValue =
   HeaderType_ethernet {
     dstAddr : 0,
     srcAddr : 0,
     etherType : 0
   };
endinstance
typedef struct {
   Bit#(4) version;
   Bit#(4) ihl;
   Bit#(8) diffserv;
   Bit#(16) totalLen;
   Bit#(16) identification;
   Bit#(3) flags;
   Bit#(13) fragOffset;
   Bit#(8) ttl;
   Bit#(8) protocol;
   Bit#(16) hdrChecksum;
   Bit#(32) srcAddr;
   Bit#(32) dstAddr;
} HeaderType_ipv4 deriving(Bits, Eq);
instance DefaultValue#(HeaderType_ipv4);
   defaultValue =
   HeaderType_ipv4 {
     version : 0,
     ihl : 0,
     diffserv : 0,
     totalLen : 0,
     identification : 0,
     flags : 0,
     fragOffset : 0,
     ttl : 0,
     protocol : 0,
     hdrChecksum : 0,
     srcAddr : 0,
     dstAddr : 0
   };
endinstance
typedef struct {
   Bit#(9) ingress_port;
   Bit#(32) packet_length;
   Bit#(9) egress_spec;
   Bit#(9) egress_port;
   Bit#(32) egress_instance;
   Bit#(32) instance_type;
   Bit#(32) clone_spec;
   Bit#(5) _padding;
} HeaderType_standard_metadata deriving(Bits, Eq);
instance DefaultValue#(HeaderType_standard_metadata);
   defaultValue =
   HeaderType_standard_metadata {
     ingress_port : 0,
     packet_length : 0,
     egress_spec : 0,
     egress_port : 0,
     egress_instance : 0,
     instance_type : 0,
     clone_spec : 0,
     _padding : 0
   };
endinstance
typedef struct {
   Bit#(12) vrf;
   Bit#(16) bd;
   Bit#(16) nexthop_index;
   Bit#(4) _padding;
} HeaderType_ingress_metadata deriving(Bits, Eq);
instance DefaultValue#(HeaderType_ingress_metadata);
   defaultValue =
   HeaderType_ingress_metadata {
     vrf : 0,
     bd : 0,
     nexthop_index : 0,
     _padding : 0
   };
endinstance

typedef struct {
   Bit#(16) ingress_metadata_bd;
   Bit#(16) ingress_metadata_nexthop_index;
   Bit#(12) ingress_metadata_vrf;
   Bit#(32) ipv4_dstAddr;
   Bit#(9) standard_metadata_ingress_port;
   Bit#(32) header_addr;
   Bit#(32) payload_addr;
   Bit#(16) payload_len;
} PHV_table;

// Copyright (c) 2015 Cornell University.

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

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

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

import DefaultValue::*;

typedef struct {
   Bit#(48) dstAddr;
   Bit#(48) srcAddr;
   Bit#(16) etherType;
} HeaderType_ethernet deriving(Bits, Eq);
instance DefaultValue#(HeaderType_ethernet);
   defaultValue =
   HeaderType_ethernet {
     dstAddr : 0,
     srcAddr : 0,
     etherType : 0
   };
endinstance
typedef struct {
   Bit#(4) version;
   Bit#(4) ihl;
   Bit#(8) diffserv;
   Bit#(16) totalLen;
   Bit#(16) identification;
   Bit#(3) flags;
   Bit#(13) fragOffset;
   Bit#(8) ttl;
   Bit#(8) protocol;
   Bit#(16) hdrChecksum;
   Bit#(32) srcAddr;
   Bit#(32) dstAddr;
} HeaderType_ipv4 deriving(Bits, Eq);
instance DefaultValue#(HeaderType_ipv4);
   defaultValue =
   HeaderType_ipv4 {
     version : 0,
     ihl : 0,
     diffserv : 0,
     totalLen : 0,
     identification : 0,
     flags : 0,
     fragOffset : 0,
     ttl : 0,
     protocol : 0,
     hdrChecksum : 0,
     srcAddr : 0,
     dstAddr : 0
   };
endinstance
typedef struct {
   Bit#(9) ingress_port;
   Bit#(32) packet_length;
   Bit#(9) egress_spec;
   Bit#(9) egress_port;
   Bit#(32) egress_instance;
   Bit#(32) instance_type;
   Bit#(32) clone_spec;
   Bit#(5) _padding;
} HeaderType_standard_metadata deriving(Bits, Eq);
instance DefaultValue#(HeaderType_standard_metadata);
   defaultValue =
   HeaderType_standard_metadata {
     ingress_port : 0,
     packet_length : 0,
     egress_spec : 0,
     egress_port : 0,
     egress_instance : 0,
     instance_type : 0,
     clone_spec : 0,
     _padding : 0
   };
endinstance
typedef struct {
   Bit#(12) vrf;
   Bit#(16) bd;
   Bit#(16) nexthop_index;
   Bit#(4) _padding;
} HeaderType_ingress_metadata deriving(Bits, Eq);
instance DefaultValue#(HeaderType_ingress_metadata);
   defaultValue =
   HeaderType_ingress_metadata {
     vrf : 0,
     bd : 0,
     nexthop_index : 0,
     _padding : 0
   };
endinstance

// Match structs
typedef struct {
   Bit#(16) dlEtherType;
   Bit#(32) src;
   Bit#(32) dst;
} MatchEntry deriving (Bits, Eq);
instance DefaultValue#(MatchEntry);
   defaultValue =
   MatchEntry {
     dlEtherType : 0,
     src : 0,
     dst : 0
   };
endinstance

// Action structs
typedef struct {
   Bit#(32) ipv4;
   Bit#(48) stats;
   Bit#(32) insts;
   Bit#(16) actions;
} ActionEntry deriving (Bits, Eq);
instance DefaultValue#(ActionEntry);
   defaultValue =
   ActionEntry {
      ipv4 : 0,
      stats : 0,
      insts : 0,
      actions : 0
   };
endinstance


updated ImageonPcieTop.bsv

updated ImageonPcieTop.bsv

Change-Id: Ie782943960696c966903455c620cc11b62f74879

// 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 Vector            :: *;
import GetPut            :: *;
import Connectable       :: *;
import Xilinx            :: *;
import XilinxCells       :: *;
import X7PcieSplitter    :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiSlaveEngine    :: *;
import AxiMasterEngine   :: *;
import AxiMasterSlave    :: *;
import AxiDma            :: *;
import AxiCsr            :: *;
import HDMI::*;
import Imageon::*;

typedef (function Module#(PortalTop#(40, dsz, ipins)) mkPortalTop(Clock clock200, Clock io_vita_clk)) MkPortalTop#(numeric type dsz, type ipins);

`ifdef Artix7
typedef 4 PcieLanes;
typedef 4 NumLeds;
`else
typedef 8 PcieLanes;
typedef 8 NumLeds;
`endif

interface PcieTop#(type ipins);
   (* prefix="PCIE" *)
   interface PCIE_EXP#(PcieLanes) pcie;
   (* always_ready *)
   method Bit#(NumLeds) leds();
   interface ipins       pins;
endinterface

(* no_default_clock, no_default_reset *)
module [Module] mkPcieTopFromPortal #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
				      Clock sys_clk_p,     Clock sys_clk_n,
				      Clock io_vita_clk_out_p, Clock io_vita_clk_out_n,
				      Reset pci_sys_reset_n,
				      MkPortalTop#(dsz, ipins) mkPortalTop)
   (PcieTop#(ipins))
   provisos (Mul#(TDiv#(dsz, 32), 32, dsz),
	     Add#(b__, 32, dsz),
	     Add#(c__, dsz, 256),
	     Add#(d__, TMul#(8, TDiv#(dsz, 32)), 64),
	     Add#(e__, TMul#(32, TDiv#(dsz, 32)), 256),
	     Add#(f__, TDiv#(dsz, 32), 8),
	     Mul#(TDiv#(dsz, 8), 8, dsz)
      );

   let contentId = 0;

   X7PcieSplitter#(PcieLanes) x7pcie <- mkX7PcieSplitter(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,
							 contentId );

   // instantiate user portals
   Clock io_vita_clk <- XilinxCells::mkClockIBUFDS(io_vita_clk_out_p, io_vita_clk_out_n);
   let portalTop <- mkPortalTop(x7pcie.clock200, io_vita_clk, clocked_by x7pcie.clock125, reset_by x7pcie.portalReset);

   AxiSlaveEngine#(dsz) axiSlaveEngine <- mkAxiSlaveEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   AxiMasterEngine axiMasterEngine <- mkAxiMasterEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(tpl_1(x7pcie.slave), tpl_2(axiSlaveEngine.tlps), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(axiSlaveEngine.tlps), tpl_2(x7pcie.slave), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   Axi3Master#(40,dsz,6) m_axi <- mkAxiDmaMaster(portalTop.master,clocked_by x7pcie.clock125, reset_by x7pcie.portalReset);
   mkConnection(m_axi, axiSlaveEngine.slave, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(tpl_1(x7pcie.master), axiMasterEngine.tlp_in);
   mkConnection(axiMasterEngine.tlp_out, tpl_2(x7pcie.master));

   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(portalTop.slave, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(axiMasterEngine.master, ctrl, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // going from level to edge-triggered interrupt
   Vector#(15, Reg#(Bool)) interruptRequested <- replicateM(mkReg(False, clocked_by x7pcie.clock125, reset_by x7pcie.reset125));
   for (Integer i = 0; i < 15; i = i + 1) begin
      // intr_num 0 for the directory
      Integer intr_num = i+1;
      MSIX_Entry msixEntry = x7pcie.msixEntry[intr_num];
      rule interruptRequest;
	 if (portalTop.interrupt[i] && !interruptRequested[i])
	    axiMasterEngine.interruptRequest.put(tuple2({msixEntry.addr_hi, msixEntry.addr_lo}, msixEntry.msg_data));
	 interruptRequested[i] <= portalTop.interrupt[i];
      endrule
   end

   interface pcie = x7pcie.pcie;
   //interface ddr3 = x7pcie.ddr3;
   method Bit#(NumLeds) leds();
      return extend({pack(x7pcie.isLinkUp()),3'd2});
   endmethod
   interface pins = portalTop.pins;

endmodule: mkPcieTopFromPortal

(* synthesize *)
module mkSynthesizeablePortalTop#(Clock clock200, Clock io_vita_clk)(PortalTop#(40, 64, ImageCapturePins));
   let top <- mkPortalTop(clock200, io_vita_clk);
   interface master = top.master;
   interface slave = top.slave;
   interface interrupt = top.interrupt;
   interface leds = top.leds;
   interface pins = top.pins;
endmodule

module mkImageonPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
   Clock sys_clk_p,     Clock sys_clk_n,
   Clock io_vita_clk_out_p, Clock io_vita_clk_out_n,
   Reset pci_sys_reset_n)
   (PcieTop#(ImageCapturePins));

   let top <- mkPcieTopFromPortal(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n,
				  io_vita_clk_out_p, io_vita_clk_out_n,
				  pci_sys_reset_n,
				  mkSynthesizeablePortalTop);
   return top;
endmodule: mkImageonPcieTop

// 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 Vector            :: *;
import Connectable       :: *;
import Xilinx            :: *;
import XilinxCells       :: *;
import X7PcieSplitter    :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiSlaveEngine    :: *;
import AxiMasterEngine   :: *;
import HDMI::*;
import Imageon::*;

typedef (function Module#(PortalTop#(40, dsz, ipins)) mkPortalTop(Clock clock200, Clock io_vita_clk)) MkPortalTop#(numeric type dsz, type ipins);

`ifdef Artix7
typedef 4 PcieLanes;
typedef 4 NumLeds;
`else
typedef 8 PcieLanes;
typedef 8 NumLeds;
`endif

interface PcieTop#(type ipins);
   (* prefix="PCIE" *)
   interface PCIE_EXP#(PcieLanes) pcie;
   (* always_ready *)
   method Bit#(NumLeds) leds();
   interface ipins       pins;
endinterface

(* no_default_clock, no_default_reset *)
module [Module] mkPcieTopFromPortal #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
				      Clock sys_clk_p,     Clock sys_clk_n,
				      Clock io_vita_clk_out_p, Clock io_vita_clk_out_n,
				      Reset pci_sys_reset_n,
				      MkPortalTop#(dsz, ipins) mkPortalTop)
   (PcieTop#(ipins))
   provisos (Mul#(TDiv#(dsz, 32), 32, dsz),
	     Add#(b__, 32, dsz),
	     Add#(c__, dsz, 256),
	     Add#(d__, TMul#(8, TDiv#(dsz, 32)), 64),
	     Add#(e__, TMul#(32, TDiv#(dsz, 32)), 256),
	     Add#(f__, TDiv#(dsz, 32), 8)
      );

   let contentId = 0;

   X7PcieSplitter#(PcieLanes) x7pcie <- mkX7PcieSplitter(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,
							 contentId );

   Reg#(Bool) interruptRequested <- mkReg(False, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // instantiate user portals
   Clock io_vita_clk <- XilinxCells::mkClockIBUFDS(io_vita_clk_out_p, io_vita_clk_out_n);
   let portalTop <- mkPortalTop(x7pcie.clock200, io_vita_clk, clocked_by x7pcie.clock125, reset_by x7pcie.portalReset);

   AxiSlaveEngine#(dsz) axiSlaveEngine <- mkAxiSlaveEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   AxiMasterEngine axiMasterEngine <- mkAxiMasterEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(tpl_1(x7pcie.slave), tpl_2(axiSlaveEngine.tlps), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(axiSlaveEngine.tlps), tpl_2(x7pcie.slave), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(portalTop.m_axi, axiSlaveEngine.slave, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   mkConnection(tpl_1(x7pcie.master), axiMasterEngine.tlp_in);
   mkConnection(axiMasterEngine.tlp_out, tpl_2(x7pcie.master));

   mkConnection(axiMasterEngine.master, portalTop.ctrl, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   rule interruptConfig;
      axiMasterEngine.interruptAddr <= x7pcie.interruptAddr;
      axiMasterEngine.interruptData <= x7pcie.interruptData;
   endrule

   // going from level to edge-triggered interrupt
   rule interruptRequest;
      if (portalTop.interrupt && !interruptRequested)
	 axiMasterEngine.interruptRequested <= True;
      interruptRequested <= portalTop.interrupt;
   endrule

   interface pcie = x7pcie.pcie;
   //interface ddr3 = x7pcie.ddr3;
   method Bit#(NumLeds) leds();
      return extend({pack(x7pcie.isLinkUp()),3'd2});
   endmethod
   interface pins = portalTop.pins;

endmodule: mkPcieTopFromPortal

(* synthesize *)
module mkSynthesizeablePortalTop#(Clock clock200, Clock io_vita_clk)(PortalTop#(40, 64, ImageonVita));
   let top <- mkPortalTop(clock200, io_vita_clk);
   interface ctrl = top.ctrl;
   interface read_client = top.read_client;
   interface write_clinet = top.write_client;
   interface interrupt = top.interrupt;
   interface leds = top.leds;
   interface pins = top.pins;
endmodule

module mkImageonPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
   Clock sys_clk_p,     Clock sys_clk_n,
   Clock io_vita_clk_out_p, Clock io_vita_clk_out_n,
   Reset pci_sys_reset_n)
   (PcieTop#(ImageonVita));

   let top <- mkPcieTopFromPortal(pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n,
				  io_vita_clk_out_p, io_vita_clk_out_n,
				  pci_sys_reset_n,
				  mkSynthesizeablePortalTop);
   return top;
endmodule: mkImageonPcieTop


formal parameter cmd was shadowing a global, renamed to _cmd, stupid language

// 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 BRAMFIFO::*;
import GetPut::*;
import StmtFSM::*;
import ClientServer::*;

import PortalMemory::*;
import PortalRMemory::*;
import GetPutF::*;

import RingTypes::*;
import RingBuffer::*;
import CopyEngine::*;
import EchoEngine::*;
import NopEngine::*;

interface RingRequest;
   method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
   method Action get(Bit#(1) cmd, Bit#(2) regist);
   method Action hwenable(Bit#(1) en);
   method Action doCommandIndirect(Bit#(32) addr);
   method Action doCommandImmediate(Bit#(64) data);
endinterface

interface RingIndication;
   method Action setResult(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
   method Action getResult(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
   method Action completion(Bit#(32) command, Bit#(32) tag);
endinterface

module mkRingRequest#(RingIndication indication,
		      DMAReadServer#(64) dma_read_chan,
		      DMAWriteServer#(64) dma_write_chan,
		      DMAReadServer#(64) cmd_read_chan,
		      DMAWriteServer#(64) status_write_chan )(RingRequest);
   DMAReadBuffer#(64,8) copy_read_chan <- mkDMAReadBuffer();
   DMAWriteBuffer#(64,8) copy_write_chan <- mkDMAWriteBuffer();

   ServerF#(Bit#(64), Bit#(64)) copyEngine <- mkCopyEngine(dma_read_chan, dma_write_chan);
   ServerF#(Bit#(64), Bit#(64)) nopEngine <- mkNopEngine();
   ServerF#(Bit#(64), Bit#(64)) echoEngine <- mkEchoEngine();

   RingBuffer cmdRing <- mkRingBuffer;
   RingBuffer statusRing <- mkRingBuffer;
   Reg#(Bool) hwenabled <- mkReg(False);
   Reg#(Bool) cmdBusy <- mkReg(False);
   Reg#(UInt#(64)) cmd <- mkReg(0);
   Reg#(Bit#(4)) ii <- mkReg(0);
   Reg#(Bit#(4)) respCtr <- mkReg(0);

   let engineselect = pack(cmd)[63:56];
   function ServerF#(Bit#(64), Bit#(64)) cmdifc();
      if (engineselect == zeroExtend(pack(CmdNOP)))
	 return nopEngine;
      else if (engineselect == zeroExtend(pack(CmdCOPY)))
	 return copyEngine;
      else if (engineselect == zeroExtend(pack(CmdECHO)))
	 return echoEngine;
      else
	 return nopEngine;
   endfunction

   Stmt cmdFetch =   seq
      while (True) seq
	 while(!(hwenabled && cmdRing.notEmpty())) noAction;
	 cmd_read_chan.readReq.put(
	    DMAAddressRequest{handle: cmdRing.memhandle,
	       address: cmdRing.bufferlast, burstLen: 8, tag: 0});
	 cmdRing.pop(64);
      endseq
		     endseq;

   Stmt cmdDispatch =
   seq
      while (True) seq
	 cmd <= cmd_read_chan.readData.first().data;
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd);
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
	 cmdifc.put(cmd_read_chan.readData.first().data);
	 cmd_read_chan.readData.deq();
      endseq
   endseq;

   Stmt cmdCompletion =
   seq
      while(True) seq
	 while(!(hwenabled && statusRing.notFull())) noAction;
      endseq
   endseq;

   Stmt responseArbiter =
   seq
      while(True) seq
	 if (statusRing.notFull() && copyEngine.response.notEmpty())
	    seq
	       status_write_chan.writeReq.put(
		  DMAAddressRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       statusRing.push(64);
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  status_write_chan.writeData.put(
		     DMAData{data:copyEngine.get(), tag: 0});
	    endseq

	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    seq
	       status_write_chan.writeReq.put(
		  DMAAddressRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       statusRing.push(64);
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  status_write_chan.writeData.put(
		     DMAData{data:echoEngine.get(), tag: 0});
	    endseq

	       action
		  status_write_chan.writeData.put(echoEngine.get());
		  statusRing.push(8);
	       endaction
      endseq
   endseq;

   mkAutoFSM (cmdFetch);
   mkAutoFSM (cmdDispatch);
   mkAutoFSM (cmdCompletion);

      // to start a command, doCommand fires off a memory read to the
      // specified address. when it comes back, the doCommandRule will
      // handle it
      method Action doCommandIndirect(Bit#(DmaAddrSize) addr);
	 //cmd_read_chan.readReq.put(addr);
      endmethod

      method Action doCommandImmediate(Bit#(64) data);
      	 $display("doCommandImmediate %h", data);
      endmethod

      method Action set(Bit#(1) _cmd, Bit#(2) regist, Bit#(32) addr);
	 if (_cmd == 1)
	    cmdRing.set(regist, addr);
	 else
	    statusRing.set(regist, addr);
	 indication.ringIndication.setResult(cmd, regist, addr);
      endmethod

      method Action get(Bit#(1) _cmd, Bit#(2) regist);
	 if (_cmd == 1)
	    indication.ringIndication.getResult(1, regist, cmdRing.get(regist));
	 else
	    indication.ringIndication.getResult(0, regist,
	       statusRing.get(regist));
      endmethod

      method Action hwenable(Bit#(1) en);
	 hwenabled <= en == 1;
      endmethod

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 FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;
import StmtFSM::*;
import ClientServer::*;

import PortalMemory::*;
import PortalRMemory::*;
import GetPutF::*;

import RingTypes::*;
import RingBuffer::*;
import CopyEngine::*;
import EchoEngine::*;
import NopEngine::*;

interface RingRequest;
   method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
   method Action get(Bit#(1) cmd, Bit#(2) regist);
   method Action hwenable(Bit#(1) en);
   method Action doCommandIndirect(Bit#(32) addr);
   method Action doCommandImmediate(Bit#(64) data);
endinterface

interface RingIndication;
   method Action setResult(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
   method Action getResult(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
   method Action completion(Bit#(32) command, Bit#(32) tag);
endinterface

module mkRingRequest#(RingIndication indication,
		      DMAReadServer#(64) dma_read_chan,
		      DMAWriteServer#(64) dma_write_chan,
		      DMAReadServer#(64) cmd_read_chan,
		      DMAWriteServer#(64) status_write_chan )(RingRequest);
   DMAReadBuffer#(64,8) copy_read_chan <- mkDMAReadBuffer();
   DMAWriteBuffer#(64,8) copy_write_chan <- mkDMAWriteBuffer();

   ServerF#(Bit#(64), Bit#(64)) copyEngine <- mkCopyEngine(dma_read_chan, dma_write_chan);
   ServerF#(Bit#(64), Bit#(64)) nopEngine <- mkNopEngine();
   ServerF#(Bit#(64), Bit#(64)) echoEngine <- mkEchoEngine();

   RingBuffer cmdRing <- mkRingBuffer;
   RingBuffer statusRing <- mkRingBuffer;
   Reg#(Bool) hwenabled <- mkReg(False);
   Reg#(Bool) cmdBusy <- mkReg(False);
   Reg#(UInt#(64)) cmd <- mkReg(0);
   Reg#(Bit#(4)) ii <- mkReg(0);
   Reg#(Bit#(4)) respCtr <- mkReg(0);

   let engineselect = pack(cmd)[63:56];
   function ServerF#(Bit#(64), Bit#(64)) cmdifc();
      if (engineselect == zeroExtend(pack(CmdNOP)))
	 return nopEngine;
      else if (engineselect == zeroExtend(pack(CmdCOPY)))
	 return copyEngine;
      else if (engineselect == zeroExtend(pack(CmdECHO)))
	 return echoEngine;
      else
	 return nopEngine;
   endfunction

   Stmt cmdFetch =   seq
      while (True) seq
	 while(!(hwenabled && cmdRing.notEmpty())) noAction;
	 cmd_read_chan.readReq.put(
	    DMAAddressRequest{handle: cmdRing.memhandle,
	       address: cmdRing.bufferlast, burstLen: 8, tag: 0});
	 cmdRing.pop(64);
      endseq
		     endseq;

   Stmt cmdDispatch =
   seq
      while (True) seq
	 cmd <= cmd_read_chan.readData.get().data;
	 cmdifc.put(cmd);
	 cmdifc.put(cmd_read_chan.readData.get().data);
	 cmdifc.put(cmd_read_chan.readData.get().data);
	 cmdifc.put(cmd_read_chan.readData.get().data);
	 cmdifc.put(cmd_read_chan.readData.get().data);
	 cmdifc.put(cmd_read_chan.readData.get().data);
	 cmdifc.put(cmd_read_chan.readData.get().data);
	 cmdifc.put(cmd_read_chan.readData.get().data);
      endseq
   endseq;

   Stmt cmdCompletion =
   seq
      while(True) seq
	 while(!(hwenabled && statusRing.notFull())) noAction;
      endseq
   endseq;

   Stmt responseArbiter =
   seq
      while(True) seq
	 if (statusRing.notFull() && copyEngine.response.notEmpty())
	    seq
	       status_write_chan.writeReq.put(
		  DMAAddressRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       statusRing.push(64);
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  status_write_chan.writeData.put(
		     DMAData{data:copyEngine.get(), tag: 0});
	    endseq

	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    seq
	       status_write_chan.writeReq.put(
		  DMAAddressRequest{handle: statusRing.memhandle,
		     address: statusRing.bufferfirst, burstLen: 8, tag: 0});
	       statusRing.push(64);
	       for (respCtr <= 0; respCtr < 8; respCtr <= respCtr + 1)
		  status_write_chan.writeData.put(
		     DMAData{data:echoEngine.get(), tag: 0});
	    endseq

	       action
		  status_write_chan.writeData.put(echoEngine.get());
		  statusRing.push(8);
	       endaction
      endseq
   endseq;

   rule copyCompletion;
      let v <- ce.response.get();
      indication.ringIndication.completion(1, v);
   endrule

   mkAutoFSM (cmdFetch);
   mkAutoFSM (cmdDispatch);
   mkAutoFSM (cmdCompletion);

   interface RingRequest ringRequest;

      // to start a command, doCommand fires off a memory read to the
      // specified address. when it comes back, the doCommandRule will
      // handle it
      method Action doCommandIndirect(Bit#(DmaAddrSize) addr);
	 //cmd_read_chan.readReq.put(addr);
      endmethod

      method Action doCommandImmediate(Bit#(64) data);
      	 $display("doCommandImmediate %h", data);
      endmethod

      method Action set(Bit#(1) cmd, Bit#(2) regist, Bit#(32) addr);
	 if (cmd == 1)
	    cmdRing.set(regist, addr);
	 else
	    statusRing.set(regist, addr);
	 indication.ringIndication.setResult(cmd, regist, addr);
      endmethod

      method Action get(Bit#(1) cmd, Bit#(2) regist);
	 if (cmd == 1)
	    indication.ringIndication.getResult(1, regist, cmdRing.get(regist));
	 else
	    indication.ringIndication.getResult(0, regist,
	       statusRing.get(regist));
      endmethod

      method Action hwenable(Bit#(1) en);
	 hwenabled <= en == 1;
      endmethod

   endinterface

endmodule


Corrected type of word5 field in Trace_Data packet

// Copyright (c) 2013-2020 Bluespec, Inc. All Rights Reserved

// ================================================================
// Definition of Tandem Verifier Packets.
// The CPU sends out such a packet for each instruction retired.
// A Tandem Verifier contains a "golden model" simulator of the RISC-V
// ISA, and verifies that the information in the packet is correct,
// instruction by instruction.

// ================================================================

package TV_Info;

// ================================================================
// Bluespec library imports

import DefaultValue :: *;
import Vector       :: *;

// ================================================================
// Project imports

import ISA_Decls    :: *;

// ================================================================

typedef enum {// These are not from instruction flow and do not have a PC or instruction
	      TRACE_RESET,
	      TRACE_GPR_WRITE,
	      TRACE_FPR_WRITE,
	      TRACE_CSR_WRITE,
	      TRACE_MEM_WRITE,

	      // These are from instruction flow and have a PC and instruction
	      TRACE_OTHER,
	      TRACE_I_RD,   TRACE_F_GRD,   TRACE_F_FRD,
 	      TRACE_I_LOAD,  TRACE_F_LOAD,
	      TRACE_I_STORE, TRACE_F_STORE,
	      TRACE_AMO,
	      TRACE_TRAP,
	      TRACE_RET,
	      TRACE_CSRRX,

	      // These are from an interrupt and has a PC but no instruction
	      TRACE_INTR
	      } Trace_Op
deriving (Bits, Eq, FShow);

typedef struct {
   Trace_Op   op;
   WordXL     pc;
   ISize      instr_sz;
   Bit #(32)  instr;
   RegName    rd;
   WordXL     word1;
   WordXL     word2;
   Bit #(64)  word3;    // Wider than WordXL because can contain paddr (in RV32, paddr can be 34 bits)
   WordXL     word4;
`ifdef ISA_F
   Bit #(64)  word5;    // In order to accomodate RV64 MSTATUS in ISA_F system
`endif
   } Trace_Data
deriving (Bits);

// RESET
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x
function Trace_Data mkTrace_RESET ();
   Trace_Data td = ?;
   td.op       = TRACE_RESET;
   return td;
endfunction

// GPR_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                 x    rdval
function Trace_Data mkTrace_GPR_WRITE (RegName rd, WordXL rdval);
   Trace_Data td = ?;
   td.op       = TRACE_GPR_WRITE;
   td.rd       = rd;
   td.word1    = rdval;
   return td;
endfunction

// FPR_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                 x    rdval
function Trace_Data mkTrace_FPR_WRITE (RegName rd, WordXL rdval);
   Trace_Data td = ?;
   td.op       = TRACE_FPR_WRITE;
   td.rd       = rd;
   td.word1    = rdval;
   return td;
endfunction

// CSR_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                                        csraddr  csrval
function Trace_Data mkTrace_CSR_WRITE (CSR_Addr csraddr, WordXL csrval);
   Trace_Data td = ?;
   td.op       = TRACE_CSR_WRITE;
   td.word3    = zeroExtend (csraddr);
   td.word4    = csrval;
   return td;
endfunction

// MEM_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                         sz    stval    paddr
function Trace_Data mkTrace_MEM_WRITE (MemReqSize sz, WordXL stval, Bit #(64) paddr);
   Trace_Data td = ?;
   td.op       = TRACE_MEM_WRITE;
   td.word1    = zeroExtend (sz);
   td.word2    = stval;
   td.word3    = paddr;
   return td;
endfunction

// OTHER
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x
function Trace_Data mkTrace_OTHER (WordXL pc, ISize isize, Bit #(32) instr);
   Trace_Data td = ?;
   td.op       = TRACE_OTHER;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   return td;
endfunction

// I_RD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        x     rdval
function Trace_Data mkTrace_I_RD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval);
   Trace_Data td = ?;
   td.op       = TRACE_I_RD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   return td;
endfunction

`ifdef ISA_F
// F_FRD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x        x              fflags            mstatus  rdval
function Trace_Data mkTrace_F_FRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, Bit#(5) fflags, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_F_FRD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word2    = extend (fflags);
   td.word4    = mstatus;
`ifdef ISA_D
   td.word5    = rdval;
`else
   td.word5    = extend (rdval);
`endif
   return td;
endfunction

// F_GRD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x        x     rdval    fflags            mstatus
function Trace_Data mkTrace_F_GRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, Bit#(5) fflags, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_F_GRD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word2    = extend (fflags);
   td.word4    = mstatus;
   return td;
endfunction
`endif

// I_LOAD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        x     rdval             eaddr
function Trace_Data mkTrace_I_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_I_LOAD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word3    = zeroExtend (eaddr);
   return td;
endfunction

// I_STORE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x              funct3   stval    eaddr
function Trace_Data mkTrace_I_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_I_STORE;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.word1    = zeroExtend (funct3);
   td.word2    = stval;
   td.word3    = zeroExtend (eaddr);
   return td;
endfunction

`ifdef ISA_F
// F_LOAD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x        x                       eaddr    mstatus  rdval
function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, WordXL eaddr, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_F_LOAD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word3    = zeroExtend (eaddr);
   td.word4    = mstatus;
`ifdef ISA_D
   td.word5    = rdval;
`else
   td.word5    = extend (rdval);
`endif
   return td;
endfunction

// F_STORE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x              funct3            eaddr             stval
function Trace_Data mkTrace_F_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordFL stval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_F_STORE;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.word3    = zeroExtend (eaddr);
`ifdef ISA_D
   td.word5    = stval;
`else
   td.word5    = extend (stval);
`endif
   return td;
endfunction

function Trace_Data fv_trace_update_mstatus_fs (Trace_Data td, WordXL new_mstatus);
   let ntd = td;
   ntd.word4 = new_mstatus;
   return (ntd);
endfunction

function Trace_Data fv_trace_update_fcsr_fflags (Trace_Data td, Bit #(5) fflags);
   let ntd = td;
   ntd.word2 = (td.word2 | extend (fflags));
   return (ntd);
endfunction
`endif

// AMO
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        x     rdval    stval    eaddr    funct3
function Trace_Data mkTrace_AMO (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr,
				 RegName rd, WordXL rdval, WordXL stval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_AMO;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word2    = stval;
   td.word3    = zeroExtend (eaddr);
   td.word4    = zeroExtend (funct3);
   return td;
endfunction

// TRAP
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        priv  mstatus  mcause   mepc     mtval
function Trace_Data mkTrace_TRAP (WordXL pc, ISize isize, Bit #(32) instr,
				  Priv_Mode  priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
   Trace_Data td = ?;
   td.op       = TRACE_TRAP;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = zeroExtend (priv);
   td.word1    = mstatus;
   td.word2    = mcause;
   td.word3    = zeroExtend (mepc);
   td.word4    = mtval;
   return td;
endfunction

// RET
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        priv  mstatus
function Trace_Data mkTrace_RET (WordXL pc, ISize isize, Bit #(32) instr, Priv_Mode  priv, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_RET;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = zeroExtend (priv);
   td.word1    = mstatus;
   return td;
endfunction

// CSRRX
// op    pc    instr_sz    instr    rd    word1    word2              word3    word4   word5
// x     x     x           x        x     rdval    [1] mstatus_valid  csraddr  csrval  mstatus
//                                                 [0] csrvalid
function Trace_Data mkTrace_CSRRX (WordXL pc, ISize isize, Bit #(32) instr,
				   RegName rd, WordXL rdval,
				   Bool csrvalid, CSR_Addr csraddr, WordXL csrval,
				   Bool   mstatus_valid,
				   WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_CSRRX;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word2    = ((mstatus_valid ? 2 : 0) | (csrvalid ? 1 : 0));
   td.word3    = zeroExtend (csraddr);
   td.word4    = csrval;
`ifdef ISA_F
`ifdef RV32
   td.word5    = extend (mstatus);
`else
   td.word5    = mstatus;
`endif
`endif
   return td;
endfunction

// INTR
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x                          priv  mstatus  mcause   mepc     mtval
function Trace_Data mkTrace_INTR (WordXL pc,
				  Priv_Mode  priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
   Trace_Data td = ?;
   td.op       = TRACE_INTR;
   td.pc       = pc;
   td.rd       = zeroExtend (priv);
   td.word1    = mstatus;
   td.word2    = mcause;
   td.word3    = zeroExtend (mepc);
   td.word4    = mtval;
   return td;
endfunction

// ================================================================
// Display of Trace_Data for debugging

instance FShow #(Trace_Data);
   function Fmt fshow (Trace_Data td);
      Fmt fmt = $format ("Trace_Data{", fshow (td.op));

      if (td.op == TRACE_RESET) begin
      end

      else if ((td.op == TRACE_GPR_WRITE) || (td.op == TRACE_FPR_WRITE))
	 fmt = fmt + $format (" rd %0d  rdval %0h", td.rd, td.word1);

      else if (td.op == TRACE_CSR_WRITE)
	 fmt = fmt + $format (" csraddr %0h  csrval %0h", td.word3, td.word4);

      else if (td.op == TRACE_MEM_WRITE)
	 fmt = fmt + $format (" sz %0d  stval %0h  paddr %0h", td.word1, td.word2, td.word3);

      else begin
	 fmt = fmt + $format (" pc %0h", td.pc);

	 if (td.op != TRACE_INTR)
	    fmt = fmt + $format (" instr.%0d %0h:", pack (td.instr_sz), td.instr);

	 if (td.op == TRACE_I_RD)
	    fmt = fmt + $format (" rd %0d  rdval %0h", td.rd, td.word1);
`ifdef ISA_F
	 else if (td.op == TRACE_F_FRD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  fflags %05b", td.rd, td.word5, td.word2);

	 else if (td.op == TRACE_F_GRD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  fflags %05b", td.rd, td.word1, td.word2);

	 else if (td.op == TRACE_F_LOAD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  eaddr %0h",
				 td.rd, td.word5, td.word3);

	 else if (td.op == TRACE_F_STORE)
	    fmt = fmt + $format (" stval %0h  eaddr %0h", td.word5, td.word3);
`endif
	 else if (td.op == TRACE_I_LOAD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  eaddr %0h",
				 td.rd, td.word1, td.word3);

	 else if (td.op == TRACE_I_STORE)
	    fmt = fmt + $format (" stval %0h  eaddr %0h", td.word2, td.word3);

	 else if (td.op == TRACE_AMO)
	    fmt = fmt + $format (" rd %0d  rdval %0h  stval %0h  eaddr %0h",
				 td.rd, td.word1, td.word2, td.word3);

	 else if (td.op == TRACE_CSRRX)
	    fmt = fmt + $format (" rd %0d  rdval %0h  csraddr %0h  csrval %0h",
				 td.rd, td.word1, td.word3, td.word4);

	 else if ((td.op == TRACE_TRAP) || (td.op == TRACE_INTR))
	    fmt = fmt + $format (" priv %0d  mstatus %0h  mcause %0h  mepc %0h  mtval %0h",
				 td.rd, td.word1, td.word2, td.word3, td.word4);

	 else if (td.op == TRACE_RET)
	    fmt = fmt + $format (" priv %0d  mstatus %0h", td.rd, td.word1);
      end

      fmt = fmt + $format ("}");
      return fmt;
   endfunction
endinstance

// ================================================================
// Trace_Data is encoded in module mkTV_Encode into vectors of bytes,
// which are eventually streamed out to an on-line tandem verifier/
// analyzer (or to a file for off-line tandem-verification/analysis).

// Various 'transactions' produce a Trace_Data struct (e.g., reset,
// each instruction retirement, each GDB write to registers or memory,
// etc.).  Each struct is encoded into a vector of bytes; the number
// of bytes depends on the kind of transaction and various encoding
// choices.

typedef 72   TV_VB_SIZE;    // max bytes needed for each transaction
typedef  Vector #(TV_VB_SIZE, Byte)  TV_Vec_Bytes;

// ================================================================

typedef struct {
   Bit #(32)     num_bytes;
   TV_Vec_Bytes  vec_bytes;
} Info_CPU_to_Verifier deriving (Bits, FShow);

// ================================================================

endpackage

// Copyright (c) 2013-2020 Bluespec, Inc. All Rights Reserved

// ================================================================
// Definition of Tandem Verifier Packets.
// The CPU sends out such a packet for each instruction retired.
// A Tandem Verifier contains a "golden model" simulator of the RISC-V
// ISA, and verifies that the information in the packet is correct,
// instruction by instruction.

// ================================================================

package TV_Info;

// ================================================================
// Bluespec library imports

import DefaultValue :: *;
import Vector       :: *;

// ================================================================
// Project imports

import ISA_Decls    :: *;

// ================================================================

typedef enum {// These are not from instruction flow and do not have a PC or instruction
	      TRACE_RESET,
	      TRACE_GPR_WRITE,
	      TRACE_FPR_WRITE,
	      TRACE_CSR_WRITE,
	      TRACE_MEM_WRITE,

	      // These are from instruction flow and have a PC and instruction
	      TRACE_OTHER,
	      TRACE_I_RD,   TRACE_F_GRD,   TRACE_F_FRD,
 	      TRACE_I_LOAD,  TRACE_F_LOAD,
	      TRACE_I_STORE, TRACE_F_STORE,
	      TRACE_AMO,
	      TRACE_TRAP,
	      TRACE_RET,
	      TRACE_CSRRX,

	      // These are from an interrupt and has a PC but no instruction
	      TRACE_INTR
	      } Trace_Op
deriving (Bits, Eq, FShow);

typedef struct {
   Trace_Op   op;
   WordXL     pc;
   ISize      instr_sz;
   Bit #(32)  instr;
   RegName    rd;
   WordXL     word1;
   WordXL     word2;
   Bit #(64)  word3;    // Wider than WordXL because can contain paddr (in RV32, paddr can be 34 bits)
   WordXL     word4;
`ifdef ISA_F
   WordFL     word5;
`endif
   } Trace_Data
deriving (Bits);

// RESET
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x
function Trace_Data mkTrace_RESET ();
   Trace_Data td = ?;
   td.op       = TRACE_RESET;
   return td;
endfunction

// GPR_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                 x    rdval
function Trace_Data mkTrace_GPR_WRITE (RegName rd, WordXL rdval);
   Trace_Data td = ?;
   td.op       = TRACE_GPR_WRITE;
   td.rd       = rd;
   td.word1    = rdval;
   return td;
endfunction

// FPR_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                 x    rdval
function Trace_Data mkTrace_FPR_WRITE (RegName rd, WordXL rdval);
   Trace_Data td = ?;
   td.op       = TRACE_FPR_WRITE;
   td.rd       = rd;
   td.word1    = rdval;
   return td;
endfunction

// CSR_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                                        csraddr  csrval
function Trace_Data mkTrace_CSR_WRITE (CSR_Addr csraddr, WordXL csrval);
   Trace_Data td = ?;
   td.op       = TRACE_CSR_WRITE;
   td.word3    = zeroExtend (csraddr);
   td.word4    = csrval;
   return td;
endfunction

// MEM_WRITE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x                                         sz    stval    paddr
function Trace_Data mkTrace_MEM_WRITE (MemReqSize sz, WordXL stval, Bit #(64) paddr);
   Trace_Data td = ?;
   td.op       = TRACE_MEM_WRITE;
   td.word1    = zeroExtend (sz);
   td.word2    = stval;
   td.word3    = paddr;
   return td;
endfunction

// OTHER
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x
function Trace_Data mkTrace_OTHER (WordXL pc, ISize isize, Bit #(32) instr);
   Trace_Data td = ?;
   td.op       = TRACE_OTHER;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   return td;
endfunction

// I_RD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        x     rdval
function Trace_Data mkTrace_I_RD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval);
   Trace_Data td = ?;
   td.op       = TRACE_I_RD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   return td;
endfunction

`ifdef ISA_F
// F_FRD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x        x              fflags            mstatus  rdval
function Trace_Data mkTrace_F_FRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, Bit#(5) fflags, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_F_FRD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word2    = extend (fflags);
   td.word4    = mstatus;
   td.word5    = rdval;
   return td;
endfunction

// F_GRD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x        x     rdval    fflags            mstatus
function Trace_Data mkTrace_F_GRD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, Bit#(5) fflags, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_F_GRD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word2    = extend (fflags);
   td.word4    = mstatus;
   return td;
endfunction
`endif

// I_LOAD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        x     rdval             eaddr
function Trace_Data mkTrace_I_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordXL rdval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_I_LOAD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word3    = zeroExtend (eaddr);
   return td;
endfunction

// I_STORE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x              funct3   stval    eaddr
function Trace_Data mkTrace_I_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordXL stval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_I_STORE;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.word1    = zeroExtend (funct3);
   td.word2    = stval;
   td.word3    = zeroExtend (eaddr);
   return td;
endfunction

`ifdef ISA_F
// F_LOAD
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x        x                       eaddr    mstatus  rdval
function Trace_Data mkTrace_F_LOAD (WordXL pc, ISize isize, Bit #(32) instr, RegName rd, WordFL rdval, WordXL eaddr, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_F_LOAD;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word3    = zeroExtend (eaddr);
   td.word4    = mstatus;
   td.word5    = rdval;
   return td;
endfunction

// F_STORE
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4    word5
// x     x     x           x              funct3            eaddr             stval
function Trace_Data mkTrace_F_STORE (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr, WordFL stval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_F_STORE;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.word3    = zeroExtend (eaddr);
   td.word5    = stval;
   return td;
endfunction

function Trace_Data fv_trace_update_mstatus_fs (Trace_Data td, WordXL new_mstatus);
   let ntd = td;
   ntd.word4 = new_mstatus;
   return (ntd);
endfunction

function Trace_Data fv_trace_update_fcsr_fflags (Trace_Data td, Bit #(5) fflags);
   let ntd = td;
   ntd.word2 = (td.word2 | extend (fflags));
   return (ntd);
endfunction
`endif

// AMO
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        x     rdval    stval    eaddr    funct3
function Trace_Data mkTrace_AMO (WordXL pc, Bit #(3) funct3, ISize isize, Bit #(32) instr,
				 RegName rd, WordXL rdval, WordXL stval, WordXL eaddr);
   Trace_Data td = ?;
   td.op       = TRACE_AMO;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word2    = stval;
   td.word3    = zeroExtend (eaddr);
   td.word4    = zeroExtend (funct3);
   return td;
endfunction

// TRAP
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        priv  mstatus  mcause   mepc     mtval
function Trace_Data mkTrace_TRAP (WordXL pc, ISize isize, Bit #(32) instr,
				  Priv_Mode  priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
   Trace_Data td = ?;
   td.op       = TRACE_TRAP;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = zeroExtend (priv);
   td.word1    = mstatus;
   td.word2    = mcause;
   td.word3    = zeroExtend (mepc);
   td.word4    = mtval;
   return td;
endfunction

// RET
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x     x           x        priv  mstatus
function Trace_Data mkTrace_RET (WordXL pc, ISize isize, Bit #(32) instr, Priv_Mode  priv, WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_RET;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = zeroExtend (priv);
   td.word1    = mstatus;
   return td;
endfunction

// CSRRX
// op    pc    instr_sz    instr    rd    word1    word2              word3    word4   word5
// x     x     x           x        x     rdval    [1] mstatus_valid  csraddr  csrval  mstatus
//                                                 [0] csrvalid
function Trace_Data mkTrace_CSRRX (WordXL pc, ISize isize, Bit #(32) instr,
				   RegName rd, WordXL rdval,
				   Bool csrvalid, CSR_Addr csraddr, WordXL csrval,
				   Bool   mstatus_valid,
				   WordXL mstatus);
   Trace_Data td = ?;
   td.op       = TRACE_CSRRX;
   td.pc       = pc;
   td.instr_sz = isize;
   td.instr    = instr;
   td.rd       = rd;
   td.word1    = rdval;
   td.word2    = ((mstatus_valid ? 2 : 0) | (csrvalid ? 1 : 0));
   td.word3    = zeroExtend (csraddr);
   td.word4    = csrval;
`ifdef ISA_F
   td.word5    = mstatus;
`endif
   return td;
endfunction

// INTR
// op    pc    instr_sz    instr    rd    word1    word2    word3    word4
// x     x                          priv  mstatus  mcause   mepc     mtval
function Trace_Data mkTrace_INTR (WordXL pc,
				  Priv_Mode  priv, WordXL mstatus, WordXL mcause, WordXL mepc, WordXL mtval);
   Trace_Data td = ?;
   td.op       = TRACE_INTR;
   td.pc       = pc;
   td.rd       = zeroExtend (priv);
   td.word1    = mstatus;
   td.word2    = mcause;
   td.word3    = zeroExtend (mepc);
   td.word4    = mtval;
   return td;
endfunction

// ================================================================
// Display of Trace_Data for debugging

instance FShow #(Trace_Data);
   function Fmt fshow (Trace_Data td);
      Fmt fmt = $format ("Trace_Data{", fshow (td.op));

      if (td.op == TRACE_RESET) begin
      end

      else if ((td.op == TRACE_GPR_WRITE) || (td.op == TRACE_FPR_WRITE))
	 fmt = fmt + $format (" rd %0d  rdval %0h", td.rd, td.word1);

      else if (td.op == TRACE_CSR_WRITE)
	 fmt = fmt + $format (" csraddr %0h  csrval %0h", td.word3, td.word4);

      else if (td.op == TRACE_MEM_WRITE)
	 fmt = fmt + $format (" sz %0d  stval %0h  paddr %0h", td.word1, td.word2, td.word3);

      else begin
	 fmt = fmt + $format (" pc %0h", td.pc);

	 if (td.op != TRACE_INTR)
	    fmt = fmt + $format (" instr.%0d %0h:", pack (td.instr_sz), td.instr);

	 if (td.op == TRACE_I_RD)
	    fmt = fmt + $format (" rd %0d  rdval %0h", td.rd, td.word1);
`ifdef ISA_F
	 else if (td.op == TRACE_F_FRD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  fflags %05b", td.rd, td.word5, td.word2);

	 else if (td.op == TRACE_F_GRD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  fflags %05b", td.rd, td.word1, td.word2);

	 else if (td.op == TRACE_F_LOAD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  eaddr %0h",
				 td.rd, td.word5, td.word3);

	 else if (td.op == TRACE_F_STORE)
	    fmt = fmt + $format (" stval %0h  eaddr %0h", td.word5, td.word3);
`endif
	 else if (td.op == TRACE_I_LOAD)
	    fmt = fmt + $format (" rd %0d  rdval %0h  eaddr %0h",
				 td.rd, td.word1, td.word3);

	 else if (td.op == TRACE_I_STORE)
	    fmt = fmt + $format (" stval %0h  eaddr %0h", td.word2, td.word3);

	 else if (td.op == TRACE_AMO)
	    fmt = fmt + $format (" rd %0d  rdval %0h  stval %0h  eaddr %0h",
				 td.rd, td.word1, td.word2, td.word3);

	 else if (td.op == TRACE_CSRRX)
	    fmt = fmt + $format (" rd %0d  rdval %0h  csraddr %0h  csrval %0h",
				 td.rd, td.word1, td.word3, td.word4);

	 else if ((td.op == TRACE_TRAP) || (td.op == TRACE_INTR))
	    fmt = fmt + $format (" priv %0d  mstatus %0h  mcause %0h  mepc %0h  mtval %0h",
				 td.rd, td.word1, td.word2, td.word3, td.word4);

	 else if (td.op == TRACE_RET)
	    fmt = fmt + $format (" priv %0d  mstatus %0h", td.rd, td.word1);
      end

      fmt = fmt + $format ("}");
      return fmt;
   endfunction
endinstance

// ================================================================
// Trace_Data is encoded in module mkTV_Encode into vectors of bytes,
// which are eventually streamed out to an on-line tandem verifier/
// analyzer (or to a file for off-line tandem-verification/analysis).

// Various 'transactions' produce a Trace_Data struct (e.g., reset,
// each instruction retirement, each GDB write to registers or memory,
// etc.).  Each struct is encoded into a vector of bytes; the number
// of bytes depends on the kind of transaction and various encoding
// choices.

typedef 72   TV_VB_SIZE;    // max bytes needed for each transaction
typedef  Vector #(TV_VB_SIZE, Byte)  TV_Vec_Bytes;

// ================================================================

typedef struct {
   Bit #(32)     num_bytes;
   TV_Vec_Bytes  vec_bytes;
} Info_CPU_to_Verifier deriving (Bits, FShow);

// ================================================================

endpackage