Save correct address for reporting as xTVAL in the event of a fault.

// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved

package CPU_Fetch_C;

// ================================================================
// mkCPU_Fetch_C is an IMem_IFC->Module#(IMem_IFC) wrapper.

// The input parameter interface is for 32-bit-aligned 32-bit instruction-fetches.

// This module completely encapsulates the logic needed to extend it to
// 16-bit "compressed" instructions ('C' extension)
// which then also includes 16-bit-aligned 32-bit instructions.

// ================================================================
// Exports

export mkCPU_Fetch_C;

// ================================================================
// BSV lib imports

import GetPut       :: *;
import ClientServer :: *;

// ----------------
// BSV additional libs

import Cur_Cycle :: *;

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

import ISA_Decls    :: *;
import Near_Mem_IFC :: *;

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

module mkCPU_Fetch_C #(IMem_IFC  imem32) (IMem_IFC);

   // Assert: imem32.is_32b_not_16b == True

   Integer verbosity = 0;

   // This register holds the actual PC value (which can be +/-2 from
   // the address given to the ICache.
   Reg #(WordXL)  rg_pc  <- mkRegU;

   // This register holds [15:0] of a 32b instr that was in the
   // upper-half of a word from the ICache.
   Reg #(Bit #(16))  rg_instr_15_0  <- mkRegU;

   // The following hold args for the mmu-cache that are needed when
   // doing the second 32-bit fetch of an odd-aligned 32b instr
   Reg #(Bit #(3))  rg_f3          <- mkRegU;
   Reg #(Priv_Mode) rg_priv        <- mkRegU;
   Reg #(Bit #(1))  rg_sstatus_SUM <- mkRegU;
   Reg #(Bit #(1))  rg_mstatus_MXR <- mkRegU;
   Reg #(WordXL)    rg_satp        <- mkRegU;

   // Holds the faulting address
   Reg #(WordXL) rg_tval <- mkRegU;

   // ----------------------------------------------------------------

   function Bool is_even_h_pc (WordXL pc);
      return (pc [1:0] == 2'b00);
   endfunction

   function Bool is_odd_h_pc (WordXL pc);
      return (pc [1:0] != 2'b00);
   endfunction

   function Bool is_32b_instr (Bit #(n) instr);
      return (instr [1:0] == 2'b11);
   endfunction

   function Bool is_16b_instr (Bit #(n) instr);
      return (instr [1:0] != 2'b11);
   endfunction

   Bool eqw_rg_pc_imem_pc = ((imem32.pc >> 2) == (rg_pc >> 2));

   // ----------------------------------------------------------------
   // Conditions for selecting 16b and 32b instruction

   // Condition: 32b instr from {imem [15:0], rg_instr_15_0}
   Bool cond_i32_odd = (imem32.pc == rg_pc + 2);    // Assert: is_odd_h_pc (rg_pc)

   // Condition: 32b instr from imem [31:0]
   Bool cond_i32_even = (   eqw_rg_pc_imem_pc
			 && is_even_h_pc (rg_pc)
			 && (is_32b_instr (imem32.instr)));

   // Condition: 16b instr from imem [31:16]
   Bool cond_i16_odd  = (   eqw_rg_pc_imem_pc
			 && is_odd_h_pc (rg_pc)
			 && (is_16b_instr (imem32.instr [31:16])));

   // Condition: 16b instr from imem [15:0]
   Bool cond_i16_even = (   eqw_rg_pc_imem_pc
			 && is_even_h_pc (rg_pc)
			 && (is_16b_instr (imem32.instr)));

   // Condition: 32b instr from { ...next imem [15:0], imem [31:16] }
   Bool cond_i32_odd_fetch_next = (   eqw_rg_pc_imem_pc
				   && is_odd_h_pc (rg_pc)
				   && (is_32b_instr (imem32.instr [31:16])));

   // ================================================================
   // Assert: The underlying imem32 only knows about 32-bit aligned words

   rule rl_assert_fail (! imem32.is_i32_not_i16);
      $display ("ERROR: CPU_Fetch_C: imem32.is_i32_not_i16 is False");
      $finish (1);
   endrule

   rule rl_debug_conds (False && (verbosity != 0) && imem32.valid);
      $display ("    imem32.pc 0x%0h  pc 0x%0h  rg_f3 %0d  imem32.instr 0x%08h  rg_instr_15_0 0x%04h",
		imem32.pc,  rg_pc,  rg_f3,  imem32.instr,  rg_instr_15_0);
      $display ("    cond_i32_odd  = ", fshow (cond_i32_odd));
      $display ("    cond_i32_even = ", fshow (cond_i32_even));
      $display ("    cond_i16_odd  = ", fshow (cond_i16_odd));
      $display ("    cond_i16_even = ", fshow (cond_i16_even));
      $display ("    cond_i32_odd_fetch_next             = ", fshow (cond_i32_odd_fetch_next));
      $display ("    eqw_rg_pc_imem_pc                   = ", fshow (eqw_rg_pc_imem_pc));
      $display ("    is_odd_h_pc (rg_pc)                 = ", fshow (is_odd_h_pc (rg_pc)));
      $display ("    is_32b_instr (imem32.instr [31:16]) = ", fshow (is_32b_instr (imem32.instr [31:16])));
   endrule

   // ================================================================
   // On 32b odd instr in imem32.instr [31:15], fetch next 32 bits

   (* no_implicit_conditions, fire_when_enabled *)
   rule rl_fetch_next_32b (imem32.valid && cond_i32_odd_fetch_next);
      Addr next_word_addr = rg_pc + 2;
      imem32.req (rg_f3, next_word_addr, rg_priv, rg_sstatus_SUM, rg_mstatus_MXR, rg_satp);
      rg_instr_15_0 <= imem32.instr [31:16];
      rg_tval <= next_word_addr;
      if (verbosity != 0)
	 $display ("CPU_Fetch_C.rl_fetch_next_32b:  imem32.pc 0x%0h  next_word_addr 0x%0h",
		   imem32.pc, next_word_addr);
   endrule

   // ----------------
   // Compose the 'instr' 32b output

   Instr instr_out = imem32.instr;
   Bool  is_32b_not_16b = True;
   if (cond_i32_odd)
      instr_out = { imem32.instr [15:0], rg_instr_15_0 };

   else if (cond_i16_even) begin
      instr_out = { 16'b0, imem32.instr [15:0] };
      is_32b_not_16b = False;
   end

   else if (cond_i16_odd) begin
      instr_out = { 16'b0, imem32.instr [31:16] };
      is_32b_not_16b = False;
   end

   // ================================================================
   // INTERFACE

   // CPU side: IMem request
   method Action  req (Bit #(3) f3,
		       WordXL addr,
		       // The following  args for VM
		       Priv_Mode  priv,
		       Bit #(1)   sstatus_SUM,
		       Bit #(1)   mstatus_MXR,
		       WordXL     satp               // { VM_Mode, ASID, PPN_for_page_table }
		       ) if (! cond_i32_odd_fetch_next);
      rg_f3          <= f3;
      rg_pc          <= addr;
      rg_priv        <= priv;
      rg_sstatus_SUM <= sstatus_SUM;
      rg_mstatus_MXR <= mstatus_MXR;
      rg_satp        <= satp;
      rg_tval        <= addr;
      WordXL even_addr = { addr [xlen-1:2], 2'b_00 };
      imem32.req (f3, even_addr, priv, sstatus_SUM, mstatus_MXR, satp);
      if (verbosity > 0) begin
	 $display ("CPU_Fetch_C.req: addr 0x%0h, even_addr 0x%0h", addr, even_addr);
      end
   endmethod

   // CPU side: IMem response
   method Bool     valid    = (imem32.valid && (   cond_i32_odd
						|| cond_i32_even
						|| cond_i16_odd
						|| cond_i16_even));

   method Bool     is_i32_not_i16 = (cond_i32_odd || cond_i32_even);

   method WordXL   pc       = rg_pc;
   method Instr    instr    = instr_out;
   method Bool     exc      = imem32.exc;
   method Exc_Code exc_code = imem32.exc_code;
   method WordXL   tval     = rg_tval;        // Can be different from rg_pc

endmodule

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

endpackage

// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved

package CPU_Fetch_C;

// ================================================================
// mkCPU_Fetch_C is an IMem_IFC->Module#(IMem_IFC) wrapper.

// The input parameter interface is for 32-bit-aligned 32-bit instruction-fetches.

// This module completely encapsulates the logic needed to extend it to
// 16-bit "compressed" instructions ('C' extension)
// which then also includes 16-bit-aligned 32-bit instructions.

// ================================================================
// Exports

export mkCPU_Fetch_C;

// ================================================================
// BSV lib imports

import GetPut       :: *;
import ClientServer :: *;

// ----------------
// BSV additional libs

import Cur_Cycle :: *;

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

import ISA_Decls    :: *;
import Near_Mem_IFC :: *;

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

module mkCPU_Fetch_C #(IMem_IFC  imem32) (IMem_IFC);

   // Assert: imem32.is_32b_not_16b == True

   Integer verbosity = 0;

   // This register holds the actual PC value (which can be +/-2 from
   // the address given to the ICache.
   Reg #(WordXL)  rg_pc  <- mkRegU;

   // This register holds [15:0] of a 32b instr that was in the
   // upper-half of a word from the ICache.
   Reg #(Bit #(16))  rg_instr_15_0  <- mkRegU;

   // The following hold args for the mmu-cache that are needed when
   // doing the second 32-bit fetch of an odd-aligned 32b instr
   Reg #(Bit #(3))  rg_f3          <- mkRegU;
   Reg #(Priv_Mode) rg_priv        <- mkRegU;
   Reg #(Bit #(1))  rg_sstatus_SUM <- mkRegU;
   Reg #(Bit #(1))  rg_mstatus_MXR <- mkRegU;
   Reg #(WordXL)    rg_satp        <- mkRegU;

   // ----------------------------------------------------------------

   function Bool is_even_h_pc (WordXL pc);
      return (pc [1:0] == 2'b00);
   endfunction

   function Bool is_odd_h_pc (WordXL pc);
      return (pc [1:0] != 2'b00);
   endfunction

   function Bool is_32b_instr (Bit #(n) instr);
      return (instr [1:0] == 2'b11);
   endfunction

   function Bool is_16b_instr (Bit #(n) instr);
      return (instr [1:0] != 2'b11);
   endfunction

   Bool eqw_rg_pc_imem_pc = ((imem32.pc >> 2) == (rg_pc >> 2));

   // ----------------------------------------------------------------
   // Conditions for selecting 16b and 32b instruction

   // Condition: 32b instr from {imem [15:0], rg_instr_15_0}
   Bool cond_i32_odd = (imem32.pc == rg_pc + 2);    // Assert: is_odd_h_pc (rg_pc)

   // Condition: 32b instr from imem [31:0]
   Bool cond_i32_even = (   eqw_rg_pc_imem_pc
			 && is_even_h_pc (rg_pc)
			 && (is_32b_instr (imem32.instr)));

   // Condition: 16b instr from imem [31:16]
   Bool cond_i16_odd  = (   eqw_rg_pc_imem_pc
			 && is_odd_h_pc (rg_pc)
			 && (is_16b_instr (imem32.instr [31:16])));

   // Condition: 16b instr from imem [15:0]
   Bool cond_i16_even = (   eqw_rg_pc_imem_pc
			 && is_even_h_pc (rg_pc)
			 && (is_16b_instr (imem32.instr)));

   // Condition: 32b instr from { ...next imem [15:0], imem [31:16] }
   Bool cond_i32_odd_fetch_next = (   eqw_rg_pc_imem_pc
				   && is_odd_h_pc (rg_pc)
				   && (is_32b_instr (imem32.instr [31:16])));

   // ================================================================
   // Assert: The underlying imem32 only knows about 32-bit aligned words

   rule rl_assert_fail (! imem32.is_i32_not_i16);
      $display ("ERROR: CPU_Fetch_C: imem32.is_i32_not_i16 is False");
      $finish (1);
   endrule

   rule rl_debug_conds (False && (verbosity != 0) && imem32.valid);
      $display ("    imem32.pc 0x%0h  pc 0x%0h  rg_f3 %0d  imem32.instr 0x%08h  rg_instr_15_0 0x%04h",
		imem32.pc,  rg_pc,  rg_f3,  imem32.instr,  rg_instr_15_0);
      $display ("    cond_i32_odd  = ", fshow (cond_i32_odd));
      $display ("    cond_i32_even = ", fshow (cond_i32_even));
      $display ("    cond_i16_odd  = ", fshow (cond_i16_odd));
      $display ("    cond_i16_even = ", fshow (cond_i16_even));
      $display ("    cond_i32_odd_fetch_next             = ", fshow (cond_i32_odd_fetch_next));
      $display ("    eqw_rg_pc_imem_pc                   = ", fshow (eqw_rg_pc_imem_pc));
      $display ("    is_odd_h_pc (rg_pc)                 = ", fshow (is_odd_h_pc (rg_pc)));
      $display ("    is_32b_instr (imem32.instr [31:16]) = ", fshow (is_32b_instr (imem32.instr [31:16])));
   endrule

   // ================================================================
   // On 32b odd instr in imem32.instr [31:15], fetch next 32 bits

   (* no_implicit_conditions, fire_when_enabled *)
   rule rl_fetch_next_32b (imem32.valid && cond_i32_odd_fetch_next);
      Addr next_word_addr = rg_pc + 2;
      imem32.req (rg_f3, next_word_addr, rg_priv, rg_sstatus_SUM, rg_mstatus_MXR, rg_satp);
      rg_instr_15_0 <= imem32.instr [31:16];
      if (verbosity != 0)
	 $display ("CPU_Fetch_C.rl_fetch_next_32b:  imem32.pc 0x%0h  next_word_addr 0x%0h",
		   imem32.pc, next_word_addr);
   endrule

   // ----------------
   // Compose the 'instr' 32b output

   Instr instr_out = imem32.instr;
   Bool  is_32b_not_16b = True;
   if (cond_i32_odd)
      instr_out = { imem32.instr [15:0], rg_instr_15_0 };

   else if (cond_i16_even) begin
      instr_out = { 16'b0, imem32.instr [15:0] };
      is_32b_not_16b = False;
   end

   else if (cond_i16_odd) begin
      instr_out = { 16'b0, imem32.instr [31:16] };
      is_32b_not_16b = False;
   end

   // ================================================================
   // INTERFACE

   // CPU side: IMem request
   method Action  req (Bit #(3) f3,
		       WordXL addr,
		       // The following  args for VM
		       Priv_Mode  priv,
		       Bit #(1)   sstatus_SUM,
		       Bit #(1)   mstatus_MXR,
		       WordXL     satp               // { VM_Mode, ASID, PPN_for_page_table }
		       ) if (! cond_i32_odd_fetch_next);
      rg_f3          <= f3;
      rg_pc          <= addr;
      rg_priv        <= priv;
      rg_sstatus_SUM <= sstatus_SUM;
      rg_mstatus_MXR <= mstatus_MXR;
      rg_satp        <= satp;
      WordXL even_addr = { addr [xlen-1:2], 2'b_00 };
      imem32.req (f3, even_addr, priv, sstatus_SUM, mstatus_MXR, satp);
      if (verbosity > 0) begin
	 $display ("CPU_Fetch_C.req: addr 0x%0h, even_addr 0x%0h", addr, even_addr);
      end
   endmethod

   // CPU side: IMem response
   method Bool     valid    = (imem32.valid && (   cond_i32_odd
						|| cond_i32_even
						|| cond_i16_odd
						|| cond_i16_even));

   method Bool     is_i32_not_i16 = (cond_i32_odd || cond_i32_even);

   method WordXL   pc       = rg_pc;
   method Instr    instr    = instr_out;
   method Bool     exc      = imem32.exc;
   method Exc_Code exc_code = imem32.exc_code;
   method WordXL   tval     = imem32.pc;        // Can be different from rg_pc

endmodule

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

endpackage


PhysAddrWidth changes

PhysAddrWidth changes

// 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 FIFO::*;
import Connectable::*;
import Portal::*;
import HostInterface::*;
import CtrlMux::*;
import Leds::*;

// generated by tool
import SerialconfigIndication::*;
import SerialconfigRequest::*;

// defined by user
import Serialconfig::*;

typedef enum {SerialconfigIndication, SerialconfigRequest} IfcNames deriving (Eq,Bits);

module mkConnectalTop(StdConnectalTop#(PhysAddrWidth));

   // instantiate user portals
   SerialconfigIndicationProxy serialconfigIndicationProxy <- mkSerialconfigIndicationProxy(SerialconfigIndication);
   SerialconfigRequest serialconfigRequest <- mkSerialconfigRequest(serialconfigIndicationProxy.ifc);
   SerialconfigRequestWrapper serialconfigRequestWrapper <- mkSerialconfigRequestWrapper(SerialconfigRequest,serialconfigRequest);

   Vector#(2,StdPortal) portals;
   portals[0] = serialconfigRequestWrapper.portalIfc;
   portals[1] = serialconfigIndicationProxy.portalIfc;
   let ctrl_mux <- mkSlaveMux(portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = nil;
   interface leds = default_leds;

endmodule : mkConnectalTop

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

// bsv libraries
import Vector::*;
import FIFO::*;
import Connectable::*;
import Portal::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import MemTypes::*;

// generated by tool
import SerialconfigIndication::*;
import SerialconfigRequest::*;

// defined by user
import Serialconfig::*;

typedef enum {SerialconfigIndication, SerialconfigRequest} IfcNames deriving (Eq,Bits);

module mkConnectalTop(StdConnectalTop#(PhysAddrWidth));

   // instantiate user portals
   SerialconfigIndicationProxy serialconfigIndicationProxy <- mkSerialconfigIndicationProxy(SerialconfigIndication);
   SerialconfigRequest serialconfigRequest <- mkSerialconfigRequest(serialconfigIndicationProxy.ifc);
   SerialconfigRequestWrapper serialconfigRequestWrapper <- mkSerialconfigRequestWrapper(SerialconfigRequest,serialconfigRequest);

   Vector#(2,StdPortal) portals;
   portals[0] = serialconfigRequestWrapper.portalIfc;
   portals[1] = serialconfigIndicationProxy.portalIfc;
   let ctrl_mux <- mkSlaveMux(portals);

   interface interrupt = getInterruptVector(portals);
   interface slave = ctrl_mux;
   interface masters = nil;
   interface leds = default_leds;

endmodule : mkConnectalTop


clean up

clean up

// Copyright (c) 2016 P4FPGA Project

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

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

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

// Deparser Template
import Library::*;

// app-specific structs
`define DEPARSER_STRUCT
`include "DeparserGenerated.bsv"
`undef DEPARSER_STRUCT

`define COLLECT_RULE(collectrule, rl) collectrule = List::cons (rl, collectrule)

typeclass CheckForward#(type t);
   function Bool checkForward(t x);
endtypeclass
instance CheckForward#(Maybe#(Header#(t)));
   function Bool checkForward(Maybe#(Header#(t)) x);
      case (x) matches
         tagged Valid .h: begin
            return h.state matches tagged Forward ? True : False;
         end
         tagged Invalid: begin
            return False;
         end
      endcase
   endfunction
endinstance

typeclass UpdateState#(type t);
   function t updateState(t x, HeaderState state);
endtypeclass
instance UpdateState#(Maybe#(Header#(t)));
   function Maybe#(Header#(t)) updateState(Maybe#(Header#(t)) x, HeaderState state);
      case (x) matches
         tagged Valid .h: begin
            return tagged Valid Header {hdr: h.hdr, state: state};
         end
         tagged Invalid: begin
            return tagged Invalid;
         end
      endcase
   endfunction
endinstance

typedef TDiv#(PktDataWidth, 8) MaskWidth;
typedef TLog#(PktDataWidth) DataSize;
typedef TLog#(TDiv#(PktDataWidth, 8)) MaskSize;
typedef TAdd#(DataSize, 1) NumBits;
typedef TAdd#(MaskSize, 1) NumBytes;

interface Deparser;
   interface PipeIn#(MetadataT) metadata;
   interface PktWriteServer writeServer;
   interface PktWriteClient writeClient;
   method Action set_verbosity (int verbosity);
   method DeparserPerfRec read_perf_info ();
endinterface
module mkDeparser (Deparser);
   Reg#(int) cf_verbosity <- mkConfigRegU;
   function Action dbprint(Integer level, Fmt msg);
      action
      if (cf_verbosity > fromInteger(level)) begin
         $display("(%0d) ", $time, msg);
      end
      endaction
   endfunction

   FIFOF#(ByteStream#(16)) data_in_ff <- mkFIFOF;
   FIFOF#(ByteStream#(16)) data_out_ff <- mkFIFOF;
   FIFOF#(MetadataT) meta_in_ff <- mkSizedFIFOF(16);
   FIFOF#(Maybe#(Bit#(128))) data_ff <- mkDFIFOF(tagged Invalid);
   FIFO#(DeparserState) deparse_state_ff <- mkPipelineFIFO();
   Array#(Reg#(Bit#(32))) rg_next_header_len <- mkCReg(3, 0);
   Array#(Reg#(Bit#(32))) rg_buffered <- mkCReg(3, 0); // number of bytes buffered in rg_tmp
   Array#(Reg#(Bit#(32))) rg_processed <- mkCReg(3, 0); // number of bytes in current header that have been sent.
   Array#(Reg#(Bit#(32))) rg_shift_amt <- mkCReg(3, 0); // number of bytes to shift to append new bytes to rg_tmp
   Array#(Reg#(Bit#(512))) rg_tmp <- mkCReg(2, 0);
   Array#(Reg#(Bool)) deparse_done <- mkCReg(2, True);
   Array#(Reg#(Bool)) header_done <- mkCReg(2, True);
   Array#(Reg#(MetadataT)) meta <- mkCReg(2, defaultValue);
   PulseWire w_deparse_header_done <- mkPulseWire();

   let mask_this_cycle = data_in_ff.first.mask;
   let sop_this_cycle = data_in_ff.first.sop;
   let eop_this_cycle = data_in_ff.first.eop;
   let data_this_cycle = data_in_ff.first.data;
   function Action report_deparse_action(String msg, Bit#(32) buffered, Bit#(32) processed, Bit#(32) shift, Bit#(512) data);
    action
      if (cf_verbosity > 0) begin
        $display("(%0d) Deparser:report_deparse_action %s buffered %d %d %d data %h", $time, msg, buffered, processed, shift, data);
      end
    endaction
  endfunction
  function Action fetch_next_header(Bit#(32) len);
    action
      rg_next_header_len[0] <= len;
    endaction
  endfunction
  function Action move_buffered_amt(Bit#(32) len);
    action
      rg_buffered[0] <= rg_buffered[0] + len;
      rg_shift_amt[0] <= rg_shift_amt[0] + len;
    endaction
  endfunction
  function Action succeed_and_next(Bit#(32) len);
    action
      rg_processed[0] <= rg_processed[0] + len;
      rg_buffered[0] <= rg_buffered[0] - len;
    endaction
  endfunction
  function Bit#(max) create_mask(LUInt#(max) count);
    Bit#(max) v = (1 << count) - 1;
    return v;
  endfunction

  // app-specific states
  `define DEPARSER_STATE
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_STATE

  // key: we let rl_deparse_start preempts rl_deparse_payload
  (* preempts = "rl_deparse_start, rl_deparse_payload" *)
  rule rl_deparse_start if (deparse_done[1] && sop_this_cycle);
    deparse_done[1] <= False;
    header_done[1] <= False;
    let metadata = meta_in_ff.first;
    meta_in_ff.deq;
    meta[1] <= metadata;
    transit_next_state(metadata);
    dbprint(4, $format("Deparser:rl_start_state start deparse %d", valueOf(SizeOf#(DeparserState))));
    dbprint(1, $format("START deparse pkt"));
  endrule

  // process payload portion of packet, until last beat
  rule rl_deparse_payload if (deparse_done[1] && !eop_this_cycle);
    let v = data_in_ff.first;
    data_in_ff.deq;
    if (rg_shift_amt[1] != 0) begin
      Bit#(128) data_mask = create_mask(cExtend(rg_shift_amt[1]));
      Bit#(16) mask_out = create_mask(cExtend(rg_shift_amt[1] >> 3));
      let data = ByteStream { sop: v.sop, eop: v.eop, data: truncate(rg_tmp[1]) & data_mask, mask: mask_out};
      data_out_ff.enq(data);
      dbprint(4, $format("Deparser:rl_deparse_payload rg_shift_amt=%d", rg_shift_amt[1], fshow(data)));
      rg_shift_amt[1] <= 0;
    end
    else begin
      dbprint(4, $format("Deparser:rl_deparse_payload ", fshow(v)));
      data_out_ff.enq(v);
    end
  endrule

  // reset all temporary states at last beat
  rule rl_reset if (deparse_done[1] && eop_this_cycle);
    let v = data_in_ff.first;
    data_in_ff.deq;
    rg_tmp[1] <= 0;
    rg_buffered[2] <= 0;
    rg_shift_amt[2] <= 0;
    rg_processed[2] <= 0;
    dbprint(4, $format("Deparser:rl_reset"));
    data_out_ff.enq(v);
  endrule

  // from deparse state, indicate header is all parsed
  rule rl_deparse_done if (w_deparse_header_done);
    fetch_next_header(0);
    header_done[0] <= True;
    dbprint(4, $format("Deparser:rl_deparse_header_done"));
  endrule

  // wait till all processed bits are sent, cont. to send payload.
  // some data are buffered not processed.
  rule rl_wait_till_processed_done if (!deparse_done[1] && header_done[1] && (rg_processed[1] == 0));
    deparse_done[1] <= True;
    dbprint(3, $format("Deparser:rl_wait_till_processed_done"));
  endrule

  // dequeue data_in_ff during header deparsing
  rule rl_data_ff_load if (!deparse_done[1] && (rg_buffered[2] < rg_next_header_len[2]));
    dbprint(4, $format("Deparser:rl_data_ff_load %d < %d", rg_buffered[2], rg_next_header_len[2]));
    data_in_ff.deq;
  endrule

  // apply mask and send data
  // use rg_processed to keep track how much data in buffer has been processed;
  // use rg_shift_amt to keep track how much more data is yet to be processed;
  rule rl_deparse_send if (!deparse_done[1] && (rg_processed[1] > 0));
    let amt = 128;
    if (rg_processed[1] < 128) begin
       amt = rg_processed[1];
    end
    let v = data_in_ff.first;
    dbprint(3, $format("Deparser:rl_deparse_send ", fshow(v)));
    Bit#(128) data_out = truncate(rg_tmp[1] & create_mask(cExtend(amt)));
    Bit#(16) mask_out = create_mask(cExtend(amt >> 3));
    let data = ByteStream { sop: sop_this_cycle, eop: False, data: data_out, mask: mask_out };
    rg_tmp[1] <= rg_tmp[1] >> amt;
    rg_processed[1] <= rg_processed[1] - amt;
    rg_shift_amt[1] <= rg_shift_amt[1] - amt;
    data_out_ff.enq(data);
    dbprint(4, $format("Deparser:rl_deparse_send rg_processed=%d rg_shift_amt=%d amt=%d", rg_processed[1], rg_shift_amt[1], amt, fshow(data)));
  endrule

  function Rules genDeparseNextRule(PulseWire wl, DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_next if (wl);
        deparse_state_ff.enq(state);
        fetch_next_header(len);
      endrule
    endrules);
  endfunction

  function Rules genDeparseLoadRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_load if ((deparse_state_ff.first == state) && (rg_buffered[0] < len));
        rg_tmp[0] <= zeroExtend(data_this_cycle) << rg_shift_amt[0] | rg_tmp[0];
        UInt#(NumBytes) n_bytes_used = countOnes(mask_this_cycle);
        UInt#(NumBits) n_bits_used = cExtend(n_bytes_used) << 3;
        move_buffered_amt(cExtend(n_bits_used));
      endrule
    endrules);
  endfunction

  function Rules genDeparseSendRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_send if ((deparse_state_ff.first == state) && (rg_buffered[0] >= len));
        succeed_and_next(len);
        deparse_state_ff.deq;
        let metadata = meta[0];
        metadata = update_metadata(state);
        transit_next_state(metadata);
        meta[0] <= metadata;
      endrule
    endrules);
  endfunction

  List#(Rules) deparse_fsm = List::nil;

  `define DEPARSER_RULES
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_RULES

  Empty fsmrl <- addRules(foldl(rJoin, emptyRules, fsmRules));

  interface metadata = toPipeIn(meta_in_ff);
  interface PktWriteServer writeServer;
    interface writeData = toPut(data_in_ff);
  endinterface
  interface PktWriteClient writeClient;
    interface writeData = toGet(data_out_ff);
  endinterface
  method Action set_verbosity (int verbosity);
    cf_verbosity <= verbosity;
  endmethod
endmodule

// Copyright (c) 2016 P4FPGA Project

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

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

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

// Deparser Template
import Library::*;

// app-specific structs
`define DEPARSER_STRUCT
`include "DeparserGenerated.bsv"
`undef DEPARSER_STRUCT

`define COLLECT_RULE(collectrule, rl) collectrule = List::cons (rl, collectrule)

typeclass CheckForward#(type t);
   function Bool checkForward(t x);
endtypeclass
instance CheckForward#(Maybe#(Header#(t)));
   function Bool checkForward(Maybe#(Header#(t)) x);
      case (x) matches
         tagged Valid .h: begin
            return h.state matches tagged Forward ? True : False;
         end
         tagged Invalid: begin
            return False;
         end
      endcase
   endfunction
endinstance

typeclass UpdateState#(type t);
   function t updateState(t x, HeaderState state);
endtypeclass
instance UpdateState#(Maybe#(Header#(t)));
   function Maybe#(Header#(t)) updateState(Maybe#(Header#(t)) x, HeaderState state);
      case (x) matches
         tagged Valid .h: begin
            return tagged Valid Header {hdr: h.hdr, state: state};
         end
         tagged Invalid: begin
            return tagged Invalid;
         end
      endcase
   endfunction
endinstance

typedef TDiv#(PktDataWidth, 8) MaskWidth;
typedef TLog#(PktDataWidth) DataSize;
typedef TLog#(TDiv#(PktDataWidth, 8)) MaskSize;
typedef TAdd#(DataSize, 1) NumBits;
typedef TAdd#(MaskSize, 1) NumBytes;

interface Deparser;
   interface PipeIn#(MetadataT) metadata;
   interface PktWriteServer writeServer;
   interface PktWriteClient writeClient;
   method Action set_verbosity (int verbosity);
   method DeparserPerfRec read_perf_info ();
endinterface
module mkDeparser (Deparser);
   Reg#(int) cf_verbosity <- mkConfigRegU;
   function Action dbprint(Integer level, Fmt msg);
      action
      if (cf_verbosity > fromInteger(level)) begin
         $display("(%0d) ", $time, msg);
      end
      endaction
   endfunction

   FIFOF#(ByteStream#(16)) data_in_ff <- mkFIFOF;
   FIFOF#(ByteStream#(16)) data_out_ff <- mkFIFOF;
   FIFOF#(MetadataT) meta_in_ff <- mkSizedFIFOF(16);
   FIFOF#(Maybe#(Bit#(128))) data_ff <- mkDFIFOF(tagged Invalid);
   FIFO#(DeparserState) deparse_state_ff <- mkPipelineFIFO();
   Array#(Reg#(Bit#(32))) rg_next_header_len <- mkCReg(3, 0);
   Array#(Reg#(Bit#(32))) rg_buffered <- mkCReg(3, 0); // number of bytes buffered in rg_tmp
   Array#(Reg#(Bit#(32))) rg_processed <- mkCReg(3, 0); // number of bytes in current header that have been sent.
   Array#(Reg#(Bit#(32))) rg_shift_amt <- mkCReg(3, 0); // number of bytes to shift to append new bytes to rg_tmp
   Array#(Reg#(Bit#(512))) rg_tmp <- mkCReg(2, 0);
   Array#(Reg#(Bool)) deparse_done <- mkCReg(2, True);
   Array#(Reg#(Bool)) header_done <- mkCReg(2, True);
   Array#(Reg#(MetadataT)) meta <- mkCReg(2, defaultValue);
   PulseWire w_deparse_header_done <- mkPulseWire();

   let mask_this_cycle = data_in_ff.first.mask;
   let sop_this_cycle = data_in_ff.first.sop;
   let eop_this_cycle = data_in_ff.first.eop;
   let data_this_cycle = data_in_ff.first.data;
   function Action report_deparse_action(String msg, Bit#(32) buffered, Bit#(32) processed, Bit#(32) shift, Bit#(512) data);
    action
      if (cf_verbosity > 0) begin
        $display("(%0d) Deparser:report_deparse_action %s buffered %d %d %d data %h", $time, msg, buffered, processed, shift, data);
      end
    endaction
  endfunction
  function Action fetch_next_header(Bit#(32) len);
    action
      rg_next_header_len[0] <= len;
    endaction
  endfunction
  function Action move_buffered_amt(Bit#(32) len);
    action
      rg_buffered[0] <= rg_buffered[0] + len;
      rg_shift_amt[0] <= rg_shift_amt[0] + len;
    endaction
  endfunction
  function Action succeed_and_next(Bit#(32) len);
    action
      rg_processed[0] <= rg_processed[0] + len;
      rg_buffered[0] <= rg_buffered[0] - len;
    endaction
  endfunction
  function Bit#(max) create_mask(LUInt#(max) count);
    Bit#(max) v = (1 << count) - 1;
    return v;
  endfunction

  // app-specific states
  `define DEPARSER_STATE
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_STATE

  // key: we let rl_deparse_start preempts rl_deparse_payload
  (* preempts = "rl_deparse_start, rl_deparse_payload" *)
  rule rl_deparse_start if (deparse_done[1] && sop_this_cycle);
    deparse_done[1] <= False;
    header_done[1] <= False;
    let metadata = meta_in_ff.first;
    meta_in_ff.deq;
    meta[1] <= metadata;
    transit_next_state(metadata);
    dbprint(4, $format("Deparser:rl_start_state start deparse %d", valueOf(SizeOf#(DeparserState))));
    dbprint(1, $format("START deparse pkt"));
  endrule

  // process payload portion of packet, until last beat
  rule rl_deparse_payload if (deparse_done[1] && !eop_this_cycle);
    let v = data_in_ff.first;
    data_in_ff.deq;
    if (rg_shift_amt[1] != 0) begin
      Bit#(128) data_mask = create_mask(cExtend(rg_shift_amt[1]));
      Bit#(16) mask_out = create_mask(cExtend(rg_shift_amt[1] >> 3));
      let data = ByteStream { sop: v.sop, eop: v.eop, data: truncate(rg_tmp[1]) & data_mask, mask: mask_out};
      data_out_ff.enq(data);
      dbprint(4, $format("Deparser:rl_deparse_payload rg_shift_amt=%d", rg_shift_amt[1], fshow(data)));
      rg_shift_amt[1] <= 0;
    end
    else begin
      dbprint(4, $format("Deparser:rl_deparse_payload ", fshow(v)));
      data_out_ff.enq(v);
    end
  endrule

  // reset all temporary states at last beat
  rule rl_reset if (deparse_done[1] && eop_this_cycle);
    let v = data_in_ff.first;
    data_in_ff.deq;
    rg_tmp[1] <= 0;
    rg_buffered[2] <= 0;
    rg_shift_amt[2] <= 0;
    rg_processed[2] <= 0;
    dbprint(4, $format("Deparser:rl_reset"));
    data_out_ff.enq(v);
  endrule

  // from deparse state, indicate header is all parsed
  rule rl_deparse_done if (w_deparse_header_done);
    fetch_next_header(0);
    header_done[0] <= True;
    dbprint(4, $format("Deparser:rl_deparse_header_done"));
  endrule

  // wait till all processed bits are sent, cont. to send payload.
  // some data are buffered not processed.
  rule rl_wait_till_processed_done if (!deparse_done[1] && header_done[1] && (rg_processed[1] == 0));
    deparse_done[1] <= True;
    dbprint(3, $format("Deparser:rl_wait_till_processed_done"));
  endrule

  // dequeue data_in_ff during header deparsing
  rule rl_data_ff_load if (!deparse_done[1] && (rg_buffered[2] < rg_next_header_len[2]));
    dbprint(4, $format("Deparser:rl_data_ff_load %d < %d", rg_buffered[2], rg_next_header_len[2]));
    data_in_ff.deq;
  endrule

  // apply mask and send data
  // use rg_processed to keep track how much data in buffer has been processed;
  // use rg_shift_amt to keep track how much more data is yet to be processed;
  rule rl_deparse_send if (!deparse_done[1] && (rg_processed[1] > 0));
    let amt = 128;
    if (rg_processed[1] < 128) begin
       amt = rg_processed[1];
    end
    let v = data_in_ff.first;
    dbprint(3, $format("Deparser:rl_deparse_send ", fshow(v)));
    Bit#(128) data_out = truncate(rg_tmp[1] & create_mask(cExtend(amt)));
    Bit#(16) mask_out = create_mask(cExtend(amt >> 3));
    let data = ByteStream { sop: sop_this_cycle, eop: False, data: data_out, mask: mask_out };
    rg_tmp[1] <= rg_tmp[1] >> amt;
    rg_processed[1] <= rg_processed[1] - amt;
    rg_shift_amt[1] <= rg_shift_amt[1] - amt;
    data_out_ff.enq(data);
    dbprint(4, $format("Deparser:rl_deparse_send rg_processed=%d rg_shift_amt=%d amt=%d", rg_processed[1], rg_shift_amt[1], amt, fshow(data)));
  endrule

  function Rules genDeparseNextRule(PulseWire wl, DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_next if (wl);
        deparse_state_ff.enq(state);
        fetch_next_header(len);
      endrule
    endrules);
  endfunction

  function Rules genDeparseLoadRule(DeparserState state, Integer i);
    let len = fromInteger(i);
    return (rules
      rule rl_deparse_load if ((deparse_state_ff.first == state) && (rg_buffered[0] < len));
        rg_tmp[0] <= zeroExtend(data_this_cycle) << rg_shift_amt[0] | rg_tmp[0];
        UInt#(NumBytes) n_bytes_used = countOnes(mask_this_cycle);
        UInt#(NumBits) n_bits_used = cExtend(n_bytes_used) << 3;
        move_buffered_amt(cExtend(n_bits_used));
      endrule
    endrules);
  endfunction

  function Rules genDeparseSendRule();
    return (rules
      rule rl_deparse_send if ((deparse_state_ff.first == state) && (rg_buffered[0] >= len));
        succeed_and_next(len);
        deparse_state_ff.deq;
        let metadata = meta[0];
        metadata = update_metadata(state);
        transit_next_state(metadata);
        meta[0] <= metadata;
      endrule
    endrules);
  endfunction

  List#(Rules) deparse_fsm = List::nil;

  `define DEPARSER_RULES
  `include "DeparserGenerated.bsv"
  `undef DEPARSER_RULES

  Empty fsmrl <- addRules(foldl(rJoin, emptyRules, fsmRules));

  interface metadata = toPipeIn(meta_in_ff);
  interface PktWriteServer writeServer;
    interface writeData = toPut(data_in_ff);
  endinterface
  interface PktWriteClient writeClient;
    interface writeData = toGet(data_out_ff);
  endinterface
  method Action set_verbosity (int verbosity);
    cf_verbosity <= verbosity;
  endmethod
endmodule


added multi-master support to Zc706Top.bsv

Change-Id: Id255a434dffbe85b318e45f4579b7ca7ae7bb7e2

// 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 Clocks :: *;
import Vector            :: *;
import Connectable       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import XbsvXilinxCells   :: *;
import PS7LIB::*;
import PPS7LIB::*;
import XADC::*;
import FIFOF::*;
import ConnectableWithTrace::*;
import CtrlMux::*;
import AxiMasterSlave    :: *;
import AxiDma            :: *;

(* always_ready, always_enabled *)
interface ZynqTop#(type pins);
   (* prefix="" *)
   interface ZynqPins zynq;
//   (* prefix="GPIO" *)
//   interface LEDS             leds;
//   (* prefix="XADC" *)
//   interface XADC             xadc;
   interface pins             pins;
   interface Clock unused_clock;
   interface Reset unused_reset;
endinterface

typedef (function Module#(PortalTop#(32, 64, ipins, nMasters)) mkpt()) MkPortalTop#(type ipins, numeric type nMasters);

module [Module] mkZynqTopFromPortal#(MkPortalTop#(ipins,nMasters) constructor)(ZynqTop#(ipins))
   provisos(Add#(a__,nMasters,4));

   PS7 ps7 <- mkPS7();
   Clock mainclock = ps7.fclkclk[0];
   Reset mainreset = ps7.fclkreset[0];

   let top <- constructor(clocked_by mainclock, reset_by mainreset);

   Axi3Slave#(32,32,12) ctrl <- mkAxiDmaSlave(top.slave);
   mkConnection(ps7.m_axi_gp[0].client, ctrl, clocked_by mainclock, reset_by mainreset);
   Vector#(nMasters,Axi3Master#(32,64,6)) m_axis;
   if(valueOf(nMasters) > 0) begin
      m_axis[0] <- mkAxiDmaMaster(clocked_by mainclock, reset_by mainreset, top.masters[0]);
      mkConnectionWithTrace(m_axis[0], ps7.s_axi_hp[0].axi.server, clocked_by mainclock, reset_by mainreset);
   end
   if(valueOf(nMasters) > 1) begin
      m_axis[1] <- mkAxiDmaMaster(clocked_by mainclock, reset_by mainreset, top.masters[1]);
      mkConnection(m_axis[1], ps7.s_axi_hp[1].axi.server, clocked_by mainclock, reset_by mainreset);
   end
   if(valueOf(nMasters) > 2) begin
      m_axis[2] <- mkAxiDmaMaster(clocked_by mainclock, reset_by mainreset, top.masters[2]);
      mkConnection(m_axis[2], ps7.s_axi_hp[2].axi.server, clocked_by mainclock, reset_by mainreset);
   end
   if(valueOf(nMasters) > 3) begin
      m_axis[3] <- mkAxiDmaMaster(clocked_by mainclock, reset_by mainreset, top.masters[3]);
      mkConnection(m_axis[3], ps7.s_axi_hp[3].axi.server, clocked_by mainclock, reset_by mainreset);
   end

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule send_int_rule;
      ps7.interrupt(pack(intr_mux));
   endrule

   interface zynq = ps7.pins;
   // interface leds = top.leds;
   // interface XADC xadc;
   //     method Bit#(4) gpio;
   //         return 0;
   //     endmethod
   // endinterface
   interface pins = top.pins;
   interface unused_clock = mainclock;
   interface unused_reset = mainreset;
endmodule

module mkZynqTop(ZynqTop#(Empty));
   let top <- mkZynqTopFromPortal(mkPortalTop);
   return top;
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 Clocks :: *;
import Vector            :: *;
import Connectable       :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import AxiMasterSlave    :: *;
import XbsvXilinxCells   :: *;
import PS7LIB::*;
import PPS7LIB::*;
import XADC::*;
import FIFOF::*;
import ConnectableWithTrace::*;
import CtrlMux::*;

(* always_ready, always_enabled *)
interface ZynqTop#(type pins);
   (* prefix="" *)
   interface ZynqPins zynq;
//   (* prefix="GPIO" *)
//   interface LEDS             leds;
//   (* prefix="XADC" *)
//   interface XADC             xadc;
   interface pins             pins;
   interface Clock unused_clock;
   interface Reset unused_reset;
endinterface

typedef (function Module#(PortalTop#(32, 64, ipins)) mkpt()) MkPortalTop#(type ipins);

module [Module] mkZynqTopFromPortal#(MkPortalTop#(ipins) constructor)(ZynqTop#(ipins));
   PS7 ps7 <- mkPS7();
   Clock mainclock = ps7.fclkclk[0];
   Reset mainreset = ps7.fclkreset[0];

   let top <- constructor(clocked_by mainclock, reset_by mainreset);

   mkConnection(ps7.m_axi_gp[0].client, top.ctrl, clocked_by mainclock, reset_by mainreset);
   mkConnectionWithTrace(top.m_axi, ps7.s_axi_hp[0].axi.server, clocked_by mainclock, reset_by mainreset);

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule send_int_rule;
      ps7.interrupt(pack(intr_mux));
   endrule

   interface zynq = ps7.pins;
   // interface leds = top.leds;
   // interface XADC xadc;
   //     method Bit#(4) gpio;
   //         return 0;
   //     endmethod
   // endinterface
   interface pins = top.pins;
   interface unused_clock = mainclock;
   interface unused_reset = mainreset;
endmodule

module mkZynqTop(ZynqTop#(Empty));
   let top <- mkZynqTopFromPortal(mkPortalTop);
   return top;
endmodule


try for code complete, with a documentation block too!

// 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 XilinxCells::*;
import Gearbox::*;
import Pipe::*;
import BRAMFIFO::*;

(* always_enabled *)
interface FMComms1ADCPins;
   method Action io_adc_p(Bit#(14) v);
   method Action io_adc_n(Bit#(14) v);
   method Action io_adc_dco_p(Bit#(1) v);
   method Action io_adc_dco_n(Bit#(1) v);
   method Action io_adc_or_p(Bit#(1) v);
   method Action io_adc_or_n(Bit#(1) v);
endinterface

interface FMComms1ADCData;
   method Bit#(14) in_data();
   method Bit#(1) in_or();
endinterface

typedef struct {
   Bit#(14) data_i;
   Bit#(1) z_i;
   Bit#(1) or_i;
   Bit#(14) data_q;
   Bit#(1) z_q;
   Bit#(1) or_q;
   } IQ driving (Bits);

interface FMComms1ADC;
   interface FMComms1ADCPins pins;
   interface PipeOut#(IQ) adc;
endinterface

/* This module accepts inputs from an Analog Devices FMComms1
 * evaluation board Analog to Digital Converter, and delivers
 * the data as a PipeOut type on the default clock.
 *
 * Input is double data rate, with clock supplied by the FMComms1
 * Input data is 14 bits twos-complement or offset binary, plus
 * an overrange signal
 *
 * Differential inputs are converted to single ended by using Xilinx IBUFDS
 * cells. The clock is converted to single ended by an IBUFGDS cell
 *
 * DDR data is convered to SDR using IDDR cells
 * At this point, the data is a 14 bit in-phase data signal, plus in-phase
 * overrange, but a 14 bit quadrature signal, plus overrange.
 *
 * The data is packed into a 64-bit IQ datatype, with overrange as the LSB
 *
 * The 32-bit data is converted to 64-bits by a Gearbox
 *
 * Clock conversion happens 64-bits wide using a SyncBRAMFIFO, which
 * presents a PipeOut channel to the rest of the logic.
 */

module mkFMComms1ADC(FMComms1ADC);

   Clock def_clock = exposeCurrentClock;
   Reset def_reset <- exposeurrentReset;

   Vector#(14, Wire#(Bit#(1))) adc_data_p <- replicateM(mkDWire(0));
   Vector#(14, Wire#(Bit#(1))) adc_data_n <- replicateM(mkDWire(0));

   Wire#(Bit#(1)) adc_or_p <- mkDWire(0);
   Wire#(Bit#(1)) adc_or_n <- mkDWire(0);
   Wire#(Bit#(1)) adc_dco_p <- mkDWire(0);
   Wire#(Bit#(1)) adc_dco_p <- mkDWire(0);

   Vector#(14, Wire#(Bit#(1))) adc_data_p <- replicateM(mkDWire(0));
   ReadOnly#(bit#(14)) adc_data;   /* data */
   ReadOnly#(bit#(1)) adc_or;      /* overrange */
   Clock adc_dco;     /* DDR clock */

   adc_dco <- mkClockIBUFGDS(adc_dco_p, adc_dco_n);

   Reset adc_reset <- mkAsyncReset(3, def_reset, adc_dc0);

   for (Integer i = 0; i < 14; i = i + 1)
      adc_data[i] <- mkIBUFDS(adc_data_p[i], adc_data_n[i], clocked_by adc_dco);
   adc_or <- mkIBUFDS(adc_or_p, adc_or_n, clocked_by adc_dco);

   IDDRParams#(Bit#(14)) iddrparams_data = defaultValue;
   iddrparams_data.ddr_clk_edge = "SAME_EDGE_PIPELINED";
   IDDR#(Bit#(14)) adc_sdr_data <= mkIDDR(iddrparams_data, clocked_by adc_dco);

   IDDRParams#(Bit#(11)) iddrparams_or = defaultValue;
   iddrparams_or.ddr_clk_edge = "SAME_EDGE_PIPELINED";
   IDDR#(Bit#(1)) adc_sdr_or <= mkIDDR(iddrparams_or, clocked_by adc_dco);

   rule sendup_adc_data;
      adc_sdr_data.d(adc_data);
   endrule

   rule sendup_adc_data;
      adc_sdr_or.d(adc_or);
   endrule

   GearBox#(1, 2, IQ) gb <- mk1toNGearbox(adc_dco, adc_reset, adc_dco, adc_reset);
   SyncFIFOIfc#(Vector#(2, IQ)) infifo <= mkSyncBRAMFIFO(128, adc_dco, adc_reset, def_clock, def_reset);

   rule sendup_gb_data;
      gb.enq({data_i: adc_sdr_data.q1, z_i: 0, or_i: adc_sdr_or.q1,
	 data_q: adc_sdr_data.q2, z_q: 0, or_q: adc_sdr_or.q2});
   endrule

   rule sendup_adc_fifo_data;
      infifoq1.enq(gb.deq());
   endrule

   interface FMComms1ADCPins;

      method Action io_adc_data_p(Bit#(14) v);
	 for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_p[i] = v[i];
      endmethod

      method Action io_adc_data_n(Bit#(14) v);
	 for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_n[i] = v[i];
      endmethod

      method Action io_adc_dco_p(Bit#(1));
	 adc_dco_p <= v;
      endmethod

      method Action io_adc_dco_n(Bit#(1));
	 adc_dco_n <= v;
      endmethod

      method Action io_adc_or_p(Bit#(1));
	 adc_or_p <= v;
      endmethod

      method Action io_adc_or_n(Bit#(1));
	 adc_or_n <= v;
      endmethod

   endinterface;

   interface PipeOut adc;

      method IQ first();
	 return(unpack(pack(infifo.first)));
      endmethod

      method Action deq() = infifo.deq;

      method Bool notEmpty() = infifo.notEmpty;

   endinterface

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.

(* always_enabled *)
interface FMComms1ADCPins;
   method Action io_adc_p(Bit#(14) v);
   method Action io_adc_n(Bit#(14) v);
   method Action io_adc_dco_p(Bit#(1) v);
   method Action io_adc_dco_n(Bit#(1) v);
   method Action io_adc_or_p(Bit#(1) v);
   method Action io_adc_or_n(Bit#(1) v);
endinterface

interface FMComms1ADCData;
   method Bit#(14) in_data();
   method Bit#(1) in_or();
endinterface

interface FMComms1ADC;
   interface FMComms1ADCPins pins;
   interface FMComms1ADCData adc;
endinterface

module mkFMComms1ADC(FMComms1ADC);

   Vector#(14, Wire#(Bit#(1))) adc_data_p <- replicateM(mkDWire(0));
   Vector#(14, Wire#(Bit#(1))) adc_data_n <- replicateM(mkDWire(0));

   Wire#(Bit#(1)) adc_or_p <- mkDWire(0);
   Wire#(Bit#(1)) adc_or_n <- mkDWire(0);
   Wire#(Bit#(1)) adc_dco_p <- mkDWire(0);
   Wire#(Bit#(1)) adc_dco_p <- mkDWire(0);

   Vector#(14, Wire#(Bit#(1))) adc_data_p <- replicateM(mkDWire(0));
   ReadOnly#(bit#(14)) adc_data;   /* data */
   ReadOnly#(bit#(1)) adc_or;      /* overrange */
   Clock adc_dco;     /* DDR clock */

   adc_dco <- mkClockIBUFGDS(adc_dco_p, adc_dco_n);

   for (Integer i = 0; i < 14; i = i + 1)
      adc_data[i] <- mkIBUFDS(adc_data_p[i], adc_data_n[i], clocked_by adc_dco);
   adc_or <- mkIBUFDS(adc_or_p, adc_or_n, clocked_by adc_dco);

   IDDRParams#(Bit#(14)) iddrparams_data = defaultValue;
   iddrparams_data.ddr_clk_edge = "SAME_EDGE_PIPELINED";
   IDDR#(Bit#(14)) adc_sdr_data <= mkIDDR(iddrparams_data, clocked_by adc_dco);

   IDDRParams#(Bit#(11)) iddrparams_or = defaultValue;
   iddrparams_or.ddr_clk_edge = "SAME_EDGE_PIPELINED";
   IDDR#(Bit#(1)) adc_sdr_or <= mkIDDR(iddrparams_or, clocked_by adc_dco);

   rule sendup_adc_data;
      adc_sdr_data.d(adc_data);
   endrule

   rule sendup_adc_data;
      adc_sdr_or.d(adc_or);
   endrule

   interface FMComms1ADCPins;

      method Action io_adc_data_p(Bit#(14) v);
	 for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_p[i] = v[i];
      endmethod

      method Action io_adc_data_n(Bit#(14) v);
	 for (Integer i = 0; i < 14; i = i + 1)
	    adc_data_n[i] = v[i];
      endmethod

      method Action io_adc_dco_p(Bit#(1));
	 adc_dco_p <= v;
      endmethod

      method Action io_adc_dco_n(Bit#(1));
	 adc_dco_n <= v;
      endmethod

      method Action io_adc_or_p(Bit#(1));
	 adc_or_p <= v;
      endmethod

      method Action io_adc_or_n(Bit#(1));
	 adc_or_n <= v;
      endmethod

   endinterface;

endmodule


adding user-level buffering to memcpy_nobuff

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

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

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

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

import Vector::*;
import FIFOF::*;
import GetPutF::*;
import FIFO::*;
import BRAMFIFO::*;

import PortalMemory::*;
import Dma::*;
import MemreadEngine::*;
import MemwriteEngine::*;

interface MemcpyRequest;
   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
endinterface

interface MemcpyIndication;
   method Action started;
   method Action done;
endinterface

interface Memcpy;
   interface MemcpyRequest request;
   interface DmaReadClient#(64) dmaReadClient;
   interface DmaWriteClient#(64) dmaWriteClient;
endinterface

// NOTE: this test doesn't rely on mkDma[Read|Write]Buffer to ensure that
//       speculative read/write requests are not unsafely issued.  As a
//       result this must be enforced manually (mdk)

module mkMemcpy#(MemcpyIndication indication)(Memcpy);

   let rdFifo <- mkFIFOF;
   let wrFifo <- mkFIFOF;

   MemreadEngine#(64) re <- mkMemreadEngine(6'b1, rdFifo);
   MemwriteEngine#(64) we <- mkMemwriteEngine(6'b1, wrFifo);

   Reg#(Bit#(32))        rdIterCnt <- mkReg(0);
   Reg#(Bit#(32))        wrIterCnt <- mkReg(0);
   Reg#(Bit#(32))            rdCnt <- mkReg(0);
   Reg#(Bit#(32))            wrCnt <- mkReg(0);
   Reg#(DmaPointer)      rdPointer <- mkReg(0);
   Reg#(DmaPointer)      wrPointer <- mkReg(0);
   Reg#(Bit#(32))         burstLen <- mkReg(0);
   Reg#(Bit#(32))         numWords <- mkReg(0);

   FIFOF#(Bit#(64))    buffer <- mkSizedBRAMFIFOF(16);
   Reg#(Bit#(32))    rdBuffer <- mkReg(32);
   Reg#(Bit#(32))    wrBuffer <- mkReg(0);

   rule start_read(rdIterCnt > 0 && rdBuffer >= burstLen);
      //$display("start_read %d", rdCnt);
      re.start(rdPointer, extend(rdCnt*4), burstLen*4, burstLen*4);
      rdBuffer <= rdBuffer-burstLen;
      if(rdCnt+burstLen == numWords) begin
	 rdCnt <= 0;
	 rdIterCnt <= rdIterCnt-1;
      end
      else begin
	 rdCnt <= rdCnt+burstLen;
      end
   endrule

   rule start_write(wrIterCnt > 0 && wrBuffer >= burstLen);
      //$display("                    start_write %d", wrCnt);
      we.start(wrPointer, extend(wrCnt*4), burstLen*4, burstLen*4);
      wrBuffer <= wrBuffer-burstLen;
      if(wrCnt+burstLen == numWords) begin
	 wrCnt <= 0;
	 wrIterCnt <= wrIterCnt-1;
      end
      else begin
	 wrCnt <= wrCnt+burstLen;
      end
   endrule

   rule read_finish;
      //$display("read_finish %d", rdIterCnt);
      let rv0 <- re.finish;
   endrule

   rule write_finish;
      //$display("                    write_finish %d", wrIterCnt);
      let rv1 <- we.finish;
      if(wrIterCnt==0)
	 indication.done;
   endrule

   rule fill_buffer;
      rdFifo.deq;
      buffer.enq(rdFifo.first);
      wrBuffer <= wrBuffer+2;
      //$display("fill_buffer %h", rdFifo.first);
   endrule

   rule drain_buffer;
      buffer.deq;
      wrFifo.enq(buffer.first);
      rdBuffer <= rdBuffer+2;
      //$display("                    drain_buffer %h", buffer.first);
   endrule

   interface MemcpyRequest request;
   method Action startCopy(Bit#(32) wp, Bit#(32) rp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
      $display("startCopy wrPointer=%d rdPointer=%d numWords=%h burstLen=%d iterCnt=%d", wp, rp, nw, bl, ic);
      indication.started;
      // initialized
      wrPointer <= wp;
      rdPointer <= rp;
      numWords  <= nw;
      wrIterCnt <= ic;
      rdIterCnt <= ic;
      burstLen  <= bl;
   endmethod
   endinterface
   interface DmaReadClient dmaReadClient = re.dmaClient;
   interface DmaWriteClient dmaWriteClient = we.dmaClient;
endmodule

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

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

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

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

import Vector::*;
import FIFOF::*;
import GetPutF::*;
import FIFO::*;
import BRAMFIFO::*;

import PortalMemory::*;
import Dma::*;
import MemreadEngine::*;
import MemwriteEngine::*;

interface MemcpyRequest;
   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) burstLen, Bit#(32) iterCnt);
endinterface

interface MemcpyIndication;
   method Action started;
   method Action done;
endinterface

interface Memcpy;
   interface MemcpyRequest request;
   interface DmaReadClient#(64) dmaReadClient;
   interface DmaWriteClient#(64) dmaWriteClient;
endinterface

module mkMemcpy#(MemcpyIndication indication)(Memcpy);

   let readFifo <- mkFIFOF;
   let writeFifo <- mkFIFOF;

   MemreadEngine#(64) re <- mkMemreadEngine(6'b1, readFifo);
   MemwriteEngine#(64) we <- mkMemwriteEngine(6'b1, writeFifo);

   Reg#(Bit#(32))          iterCnt <- mkReg(0);
   Reg#(Bit#(32))         numWords <- mkReg(0);
   Reg#(DmaPointer)      rdPointer <- mkReg(0);
   Reg#(DmaPointer)      wrPointer <- mkReg(0);
   Reg#(Bit#(32))         burstLen <- mkReg(0);

   rule start(iterCnt > 0);
      re.start(rdPointer, 0, numWords*4, burstLen*4);
      we.start(wrPointer, 0, numWords*4, burstLen*4);
      iterCnt <= iterCnt-1;
   endrule

   rule finish;
      let rv0 <- re.finish;
      let rv1 <- we.finish;
      if(iterCnt==0)
	 indication.done;
   endrule

   rule xfer;
      //$display("xfer: %h", readFifo.first);
      readFifo.deq;
      writeFifo.enq(readFifo.first);
   endrule

   interface MemcpyRequest request;
   method Action startCopy(Bit#(32) wp, Bit#(32) rp, Bit#(32) nw, Bit#(32) bl, Bit#(32) ic);
      $display("startCopy wrPointer=%d rdPointer=%d numWords=%h burstLen=%d iterCnt=%d", wp, rp, nw, bl, ic);
      indication.started;
      // initialized
      wrPointer <= wp;
      rdPointer <= rp;
      numWords  <= nw;
      iterCnt   <= ic;
      burstLen  <= bl;
   endmethod
   endinterface
   interface DmaReadClient dmaReadClient = re.dmaClient;
   interface DmaWriteClient dmaWriteClient = we.dmaClient;
endmodule


fix spelling error

fix spelling error

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

// Idea:
// BlueScopeEvent allows one to record values only when they change,
// along with timestamps of the time of change.
// The input is some collection of bits, in some clock domain
// A trigger signal is generated when the input, anded with a trigger
// mask, changes from clock to clock
// Whenever the trigger happens, the new value and a timestamp are saved
// into a SyncBRAMFiFo.  The output of the FiFo is in the system clock
// domain, as is a counter value that says how many events have happened.
// One can request a DMA write from the FiFo to system memory, at a given
// address, for a given count.
// One can reset the fifo and counter.

import Clocks::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;
import Connectable::*;

import MemTypes::*;
import MemwriteEngine::*;
import ClientServer::*;

// This version records timestamped events
interface BlueScopeEventRequest;
   // emtpy fifo and reset event counter
   method Action doReset();
   // changes in bits selected by the mask will trigger events
   method Action setTriggerMask(Bit#(32) mask);
   // generate a report pointer indication
   method Action getCounterValue();
   // copy from fifo to memory
   method Action startDma(Bit#(32) pointer, Bit#(32) len);
endinterface

interface BlueScopeEventIndication;
   // report number of events since last reset,
   method Action counterValue(Bit#(32) v);
   // dma operation complete
   method Action dmaDone();
endinterface

interface BlueScopeEvent#(numeric type dataWidth);
   method Action dataIn(Bit#(dataWidth) d);
endinterface

interface BlueScopeEventControl#(numeric type dataWidth);
   interface BlueScopeEvent#(dataWidth) bse;
   interface BlueScopeEventRequest requestIfc;
   interface MemWriteClient#(64) writeClient;
endinterface

module mkBlueScopeEvent#(Integer samples, BlueScopeEventIndication indication)(BlueScopeEventControl#(dataWidth))
   provisos(Add#(0,dataWidth,32));

   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;
   let rv  <- mkSyncBlueScopeEvent(samples, indication, clk, rst, clk,rst);
   return rv;
endmodule

// sClk is the source? sample? side, input samples come here
// dClk is the destination? dma? side, this will generally be the system clock

module mkSyncBlueScopeEvent#(Integer samples, BlueScopeEventIndication indication, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScopeEventControl#(dataWidth))
   provisos(Add#(0, dataWidth, 32));

   // the idea here is that we let events pour into the Bram continually,
   // then reset them before starting an acquisition interval
   // we reset both halves of the fifo, not clear that is needed
   MakeResetIfc sFifoReset <- mkReset(2, True, sClk);
   MakeResetIfc dFifoReset <- mkReset(2, True, dClk);
   SyncFIFOIfc#(Bit#(64)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sFifoReset.new_rst, dClk, dFifoReset.new_rst);
   // mask reg is set from a request in the dClk domain but used in the
   // sClk domain to determine triggering
   Reg#(Bit#(dataWidth))       maskReg <- mkSyncReg(0, dClk, dRst, sClk);
   // freeClockReg counts cycles to timestamp events
   Reg#(Bit#(32)) freeClockReg <- mkReg(0, clocked_by sClk, reset_by sRst);
   // countReg counts accumulated samples
   Reg#(Bit#(32)) countReg <- mkReg(0, clocked_by sClk, reset_by sRst);
   // countSyncReg repeats that value into the dClk domain
   Reg#(Bit#(32)) countSyncReg <- mkSyncReg(0, sClk, sFifoReset.new_rst, dClk);
   // oldData is used in the sample domain, to save the previous value
   Reg#(Bit#(dataWidth)) olddata <- mkReg(0, clocked_by sClk, reset_by sRst);

   MemwriteEngine#(64, 2) mwriter <- mkMemwriteEngine;

//   (* descending_urgency = "resetState, startState" *)

   mkConnection(toGet(dfifo), toPut(mwriter.dataPipes[0]));

   rule writeDone;
      let tag <- mwriter.writeServers[0].response.get();
      indication.dmaDone;
   endrule

   rule freeClock;
      freeClockReg <= freeClockReg + 1;
   endrule

   interface BlueScopeEvent bse;

      method Action dataIn(Bit#(dataWidth) data);// if (stateReg != Idle);
	 let c = countReg;
	 if ((maskReg & (data ^ olddata)) != 0)
            begin
	       if (dfifo.notFull())
		  begin
		     dfifo.enq({data, freeClockReg});
		     countReg <= c + 1;
		     countSyncReg <= c + 1;
		  end
	       else
		  $display("bluescope.stall c=%d", c);
	    end
	 olddata <= data;
      endmethod

     endinterface

   interface BlueScopeEventRequest requestIfc;

      method Action doReset();
	 sFifoReset.assertReset();
	 dFifoReset.assertReset();
      endmethod

      method Action setTriggerMask(Bit#(32) mask);
	 maskReg <= truncate(mask);
      endmethod

      method Action getCounterValue();
         indication.counterValue(countSyncReg);
      endmethod

      method Action startDma(Bit#(32) pointer, Bit#(32) len);
	 mwriter.writeServers[0].request.put(MemengineCmd {sglId: pointer, base: 0, burstLen: 8*fromInteger(valueOf(TDiv#(dataWidth,8))), len: len, tag: ?});
      endmethod

   endinterface
   interface writeClient = mwriter.dmaClient;
endmodule

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

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

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

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

// Idea:
// BlueScopeEvent allows one to record values only when they change,
// along with timestamps of the time of change.
// The input is some collection of bits, in some clock domain
// A trigger signal is generated when the input, anded with a trigger
// mask, changes from clock to clock
// Whenever the trigger happens, the new value and a timestamp are saved
// into a SyncBRAMFiFo.  The output of the FiFo is in the system clock
// domain, as is a counter value that says how many events have happened.
// One can request a DMA write from the FiFo to system memory, at a given
// address, for a given count.
// One can reset the fifo and counter.

import Clocks::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import GetPut::*;
import Connectable::*;

import MemTypes::*;
import MemwriteEngine::*;
import ClientServer::*;

// This version records timestamped events
interface BlueScopeEventRequest;
   // emtpy fifo and reset event counter
   method Action doReset();
   // changes in bits selected by the mask will trigger events
   method Action setTriggerMask(Bit#(32) mask);
   // generate a report pointer indication
   method Action getCounterValue();
   // copy from fifo to memory
   method Action startDma(Bit#(32) pointer, Bit#(32) len);
endinterface

interface BlueScopeEventIndication;
   // report number of events since last reset,
   method Action counterValue(Bit#(32) v);
   // dma operation complete
   method Action dmaDone();
endinterface

interface BlueScopeEvent#(numeric type dataWidth);
   method Action dataIn(Bit#(dataWidth) d);
endinterface

interface BlueScopeEventControl#(numeric type dataWidth);
   interface BlueScopeEvent#(dataWidth) bse;
   interface BlueScopeEventRequest requestIfc;
   interface MemWriteClient#(64) writeClient;
endinterface

module mkBlueScopeEvent#(Integer samples, BlueScopeEventIndication indication)(BlueScopeEventControl#(dataWidth))
   provisos(Add#(0,dataWidth,32));

   let clk <- exposeCurrentClock;
   let rst <- exposeCurrentReset;
   let rv  <- mkSyncBlueScopeEvent(samples, indication, clk, rst, clk,rst);
   return rv;
endmodule

// sClk is the source? sample? side, input samples come here
// dClk is the destination? dma? side, this will generally be the system clock

module mkSyncBlueScopeEvent#(Integer samples, BlueScopeEventIndication indication, Clock sClk, Reset sRst, Clock dClk, Reset dRst)(BlueScopeEventControl#(dataWidth))
   provisos(Add#(0, dataWidth, 32));

   // the idea here is that we let events pour into the Bram continually,
   // then reset them before starting an acquisition interval
   // we reset both halves of the fifo, not clear that is needed
   MakeResetIfc sFifoReset <- mkReset(2, True, sClk);
   MakeResetIfc dFifoReset <- mkReset(2, True, dClk);
   SyncFIFOIfc#(Bit#(64)) dfifo <- mkSyncBRAMFIFO(samples, sClk, sFifoReset.new_rst, dClk, dFifoReset.new_rst);
   // mask reg is set from a request in the dClk domain but used in the
   // sClk domain to determine triggering
   Reg#(Bit#(dataWidth))       maskReg <- mkSyncReg(0, dClk, dRst, sClk);
   // freeClockReg counts cycles to timestamp events
   Reg#(Bit#(32)) freeClockReg <- mkReg(0, clocked_by sClk, reset_by sRst);
   // countReg counts accumulated samples
   Reg#(Bit#(32)) countReg <- mkReg(0, clocked_by sClk, reset_by sRst);
   // countSyncReg repeats that value into the dClk domain
   Reg#(Bit#(32)) countSyncReg <- mkSyncReg(0, sClk, sFifoReset.new_rst, dClk);
   // oldData is used in the sample domain, to save the previous value
   Reg#(Bit#(dataWidth)) olddata <- mkReg(0, clocked_by sClk, reset_by sRst);

   MemwriteEngine#(64, 2) mwriter <- mkMemwriteEngine;

//   (* descending_urgency = "resetState, startState" *)

   mkConnection(toGet(dfifo), toPut(mwriter.dataPipes[0]));

   rule writeDone;
      let tag <- mwriter.writeServers[0].response.get();
      indication.dmaDone;
   endrule

   rule freeClock;
      freeClockReg <= freeClockreg + 1;
   endrule

   interface BlueScopeEvent bse;

      method Action dataIn(Bit#(dataWidth) data);// if (stateReg != Idle);
	 let c = countReg;
	 if ((maskReg & (data ^ olddata)) != 0)
            begin
	       if (dfifo.notFull())
		  begin
		     dfifo.enq({data, freeClockReg});
		     countReg <= c + 1;
		     countSyncReg <= c + 1;
		  end
	       else
		  $display("bluescope.stall c=%d", c);
	    end
	 olddata <= data;
      endmethod

     endinterface

   interface BlueScopeEventRequest requestIfc;

      method Action doReset();
	 sFifoReset.assertReset();
	 dFifoReset.assertReset();
      endmethod

      method Action setTriggerMask(Bit#(32) mask);
	 maskReg <= truncate(mask);
      endmethod

      method Action getCounterValue();
         indication.counterValue(countSyncReg);
      endmethod

      method Action startDma(Bit#(32) pointer, Bit#(32) len);
	 mwriter.writeServers[0].request.put(MemengineCmd {sglId: pointer, base: 0, burstLen: 8*fromInteger(valueOf(TDiv#(dataWidth,8))), len: len, tag: ?});
      endmethod

   endinterface
   interface writeClient = mwriter.dmaClient;
endmodule