Ensure that halt asserted after ndm reset is not ignored.

Issue halt if haltreq is asserted and the hart is running.  This
will ensure that the hart is always halted after ndmreset, as is
done with OpenOCD.

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

package DM_Run_Control;

// ================================================================
// This package implements the 'Run Control' part of the RISC-V Debug
// Module, i.e., reset platform, reset hart, run/halt hart

// ================================================================
// BSV library imports

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

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

import ISA_Decls :: *;
import DM_Common :: *;

// ================================================================
// Interface

interface DM_Run_Control_IFC;
   method Bool   dmactive;
   method Action reset;

   // ----------------
   // DMI facing GDB/host
   method ActionValue #(DM_Word) av_read  (DM_Addr dm_addr);
   method Action  write (DM_Addr dm_addr, DM_Word dm_word);

   // ----------------
   // Facing a hart: reset and run-control
   interface Get #(Token)         hart0_get_reset_req;
   interface Client #(Bool, Bool) hart0_client_run_halt;
   interface Get #(Bit #(4))      hart0_get_other_req;

   // ----------------
   // Facing Platform: Non-Debug-Module Reset (reset all except DM)
   interface Get #(Token) get_ndm_reset_req;
endinterface

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

(* synthesize *)
module mkDM_Run_Control (DM_Run_Control_IFC);

   Integer verbosity = 0;    // Normally 0; non-zero for debugging

   // ----------------------------------------------------------------
   // NDM Reset

   FIFOF #(Token) f_ndm_reset_reqs <- mkFIFOF;

   // ----------------------------------------------------------------
   // Hart0 run control

   Reg #(Bool) rg_hart0_running <- mkRegU;

   // Reset requests to hart
   FIFOF #(Token) f_hart0_reset_reqs <- mkFIFOF;

   // Run/halt requests to hart and responses
   FIFOF #(Bool)  f_hart0_run_halt_reqs   <- mkFIFOF;
   FIFOF #(Bool)  f_hart0_run_halt_rsps   <- mkFIFOF;

   // Non-standard requests to hart and responses
   // Currently only verbosity
   FIFOF #(Bit #(4)) f_hart0_other_reqs <- mkFIFOF;

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

   Bit #(32) haltregion0 = { 31'h0, pack (! rg_hart0_running) };
   Bit #(32) haltsum     = { 31'h0, pack (! rg_hart0_running) };

   // ----------------------------------------------------------------
   // rg_dmstatus
   // Since we currently support only 1 hart,
   //     'anyXX' = 'allXX'
   //     'allrunning' = NOT 'allhalted'

   Reg#(Bool) rg_dmstatus_allresumeack <- mkRegU;

   Bool dmstatus_allresumeack   = rg_dmstatus_allresumeack;
   Bool dmstatus_anyresumeack   = rg_dmstatus_allresumeack;

   Bool dmstatus_allnonexistent = False;
   Bool dmstatus_anynonexistent = dmstatus_allnonexistent;

   Bool dmstatus_allunavail     = False;
   Bool dmstatus_anyunavail     = dmstatus_allunavail;

   Bool dmstatus_allrunning     = rg_hart0_running;
   Bool dmstatus_anyrunning     = dmstatus_allrunning;

   Bool dmstatus_allhalted      = (! rg_hart0_running);
   Bool dmstatus_anyhalted      = dmstatus_allhalted;

   DM_Word virt_rg_dmstatus = {14'b0,
			       pack (dmstatus_allresumeack),
			       pack (dmstatus_anyresumeack),
			       pack (dmstatus_allnonexistent),
			       pack (dmstatus_anynonexistent),
			       pack (dmstatus_allunavail),
			       pack (dmstatus_anyunavail),
			       pack (dmstatus_allrunning),
			       pack (dmstatus_anyrunning),
			       pack (dmstatus_allhalted),
			       pack (dmstatus_anyhalted),
			       pack (True),                     // authenticated
			       pack (False),                    // authbusy
			       1'b0,
			       pack (False),                    // devtreevalid
			       4'h2};                           // version

   // ----------------------------------------------------------------
   // rg_dmcontrol

   Reg #(Bool)  rg_dmcontrol_haltreq   <- mkRegU;
   // resumereq is a W1 field, no need for a register
   Reg #(Bool)  rg_dmcontrol_hartreset <- mkRegU;
   Reg #(Bool)  rg_dmcontrol_ndmreset  <- mkRegU;
   Reg #(Bool)  rg_dmcontrol_dmactive  <- mkReg (False);

   DM_Word virt_rg_dmcontrol = {2'b0,  // haltreq, resumereq (w-o)
				pack (rg_dmcontrol_hartreset),
				2'b0,
				pack (False),    // hasel
				10'b0,           // hartsel
				14'b0,
				pack (rg_dmcontrol_ndmreset),
				pack (rg_dmcontrol_dmactive)};

   function Action fa_rg_dmcontrol_write (DM_Word dm_word);
      action
	 let haltreq   = fn_dmcontrol_haltreq   (dm_word);
	 let resumereq = fn_dmcontrol_resumereq (dm_word);
	 let hartreset = fn_dmcontrol_hartreset (dm_word);
	 let hasel     = fn_dmcontrol_hasel     (dm_word);
	 let hartsel   = fn_dmcontrol_hartsel   (dm_word);
	 let ndmreset  = fn_dmcontrol_ndmreset  (dm_word);
	 let dmactive  = fn_dmcontrol_dmactive  (dm_word);

	 rg_dmcontrol_haltreq   <= haltreq;
	 rg_dmcontrol_hartreset <= hartreset;
	 rg_dmcontrol_ndmreset  <= ndmreset;
	 rg_dmcontrol_dmactive  <= dmactive;

	 // Debug Module reset
	 if (! dmactive) begin
	    // Reset the DM module itself
	    $display ("DM_Run_Control.write: dmcontrol 0x%08h (dmactive=0): resetting Debug Module",
		      dm_word);

	    // Error-checking
	    if (ndmreset) begin
	       $display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
			 dm_word);
	       $display ("    [1] (ndmreset) and [0] (dmactive) both asserted");
	       $display ("    dmactive has priority; ignoring ndmreset");
	    end
	    if (hartreset) begin
	       $display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
			 dm_word);
	       $display ("    [29] (hartreset) and [0] (dmactive) both asserted");
	       $display ("    dmactive has priority; ignoring hartreset");
	    end

	    // No action here; other rules will fire (see method dmactive, Debug_Module.rl_reset)
	    noAction;
	 end

	 // Platform reset (non-Debug Module)
	 else if (ndmreset) begin
	    $display ("DM_Run_Control.write: dmcontrol 0x%08h: ndmreset=1: resetting platform",
		      dm_word);
	    f_ndm_reset_reqs.enq (?);
	    rg_hart0_running <= True;    // Must be same as run/halt state of CPU after hart_reset!

	    // Error-checking
	    if (hartreset) begin
	       $display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
			 dm_word);
	       $display ("    Both ndmreset (bit 1) and hartreset (bit 29) are asserted");
	       $display ("    ndmreset has priority; ignoring hartreset");
	    end
	 end
	 else begin
	    // Deassert platform reset
	    if ((verbosity != 0) && rg_dmcontrol_ndmreset)
	       $display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing ndmreset", dm_word);

	    // Hart reset
	    if (hartreset) begin
	       if (verbosity != 0)
		  $display ("DM_Run_Control.write: dmcontrol 0x%08h: hartreset=1: resetting hart",
			    dm_word);
	       f_hart0_reset_reqs.enq (?);
	       rg_hart0_running <= True;    // Must be same as run/halt state of CPU after hart_reset!
	    end
	    else begin
	       // Deassert hart reset
	       if ((verbosity != 0) && rg_dmcontrol_hartreset)
		  $display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing hartreset", dm_word);

	       if (hasel)
		  $display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: 'hasel' is not supported",
			    dm_word);

	       if (hartsel != 0)
		  $display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: hartsel 0x%0h not supported",
			    dm_word, hartsel);

	       if (haltreq && resumereq) begin
		  $display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: haltreq=1 and resumereq=1",
			    dm_word);
		  $display ("    This behavior is 'undefined' in the spec; ignoring");
	       end
	       // Resume hart(s) if not running
	       else if (resumereq && (! rg_hart0_running)) begin
		  f_hart0_run_halt_reqs.enq (True);
		  rg_dmstatus_allresumeack <= False;
		  $display ("DM_Run_Control.write: hart0 resume request");
	       end
	       // Halt hart(s)
	       else if (haltreq && rg_hart0_running) begin
		  f_hart0_run_halt_reqs.enq (False);
		  $display ("DM_Run_Control.write: hart0 halt request");
	       end
	    end
	 end
      endaction
   endfunction

   // ----------------------------------------------------------------
   // Unimplemented

   // dm_addr_hartinfo
   // dm_addr_hawindowsel
   // dm_addr_hawindow
   // dm_addr_devtreeaddr0..3
   // dm_addr_authdata
   // dm_addr_haltregion1..31

   // ----------------------------------------------------------------
   // rg_verbosity: non-standard

   Reg #(Bit #(4)) rg_verbosity <- mkRegU;

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

   rule rl_hart0_run_rsp;
      let x = f_hart0_run_halt_rsps.first;
      f_hart0_run_halt_rsps.deq;

      rg_hart0_running <= x;
      if (x) begin
	 rg_dmstatus_allresumeack <= True;
	 $display ("DM_Run_Control: hart0 running");
      end
      else begin
	 $display ("DM_Run_Control: hart0 halted");
      end
   endrule

   // ----------------------------------------------------------------
   // INTERFACE

   method Bool dmactive;
      return rg_dmcontrol_dmactive;
   endmethod

   method Action reset;
      f_ndm_reset_reqs.clear;

      rg_hart0_running <= True;    // Must be same as run/halt state of CPU after hart_reset!
      f_hart0_reset_reqs.clear;
      f_hart0_run_halt_reqs.clear;
      f_hart0_run_halt_rsps.clear;

      rg_dmcontrol_haltreq   <= False;
      rg_dmcontrol_hartreset <= False;
      rg_dmcontrol_ndmreset  <= False;
      rg_dmcontrol_dmactive  <= True;    // DM module is now active

      rg_dmstatus_allresumeack <= False;

      rg_verbosity <= 0;

      if (verbosity != 0)
	 $display ("DM_Run_Control: reset");
   endmethod

   // ----------------
   // DMI facing GDB/host

   method ActionValue #(DM_Word) av_read (DM_Addr dm_addr);
      actionvalue
	 DM_Word dm_word = case (dm_addr)
			      dm_addr_dmcontrol:   virt_rg_dmcontrol;
			      dm_addr_dmstatus:    virt_rg_dmstatus;
			      dm_addr_haltsum:     haltsum;
			      dm_addr_haltregion0: haltregion0;
			      dm_addr_verbosity:   extend (rg_verbosity);
			   endcase;

	 if (verbosity != 0)
	    $display ("DM_Run_Control.av_read: [", fshow_dm_addr (dm_addr), "] => 0x%08h", dm_word);

	 return dm_word;
      endactionvalue
   endmethod

   method Action write (DM_Addr dm_addr, DM_Word dm_word);
      action
	 if (verbosity != 0)
	    $display ("DM_Run_Control.write: [", fshow_dm_addr (dm_addr), "] <= 0x%08h", dm_word);

	 case (dm_addr)
	    dm_addr_dmcontrol: fa_rg_dmcontrol_write (dm_word);
	    dm_addr_verbosity: begin
				  rg_verbosity <= truncate (dm_word);
				  f_hart0_other_reqs.enq (truncate (dm_word));
			       end
	    default: noAction;
	 endcase
      endaction
   endmethod

   // ----------------
   // Facing Hart: Reset, Run-control, etc.
   interface Get    hart0_get_reset_req   = toGet (f_hart0_reset_reqs);
   interface Client hart0_client_run_halt = toGPClient (f_hart0_run_halt_reqs, f_hart0_run_halt_rsps);
   interface Get    hart0_get_other_req   = toGet (f_hart0_other_reqs);

   // ----------------
   // Facing Platform: Non-Debug-Module Reset (reset all except DM)
   interface Get get_ndm_reset_req = toGet (f_ndm_reset_reqs);
endmodule

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

endpackage

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

package DM_Run_Control;

// ================================================================
// This package implements the 'Run Control' part of the RISC-V Debug
// Module, i.e., reset platform, reset hart, run/halt hart

// ================================================================
// BSV library imports

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

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

import ISA_Decls :: *;
import DM_Common :: *;

// ================================================================
// Interface

interface DM_Run_Control_IFC;
   method Bool   dmactive;
   method Action reset;

   // ----------------
   // DMI facing GDB/host
   method ActionValue #(DM_Word) av_read  (DM_Addr dm_addr);
   method Action  write (DM_Addr dm_addr, DM_Word dm_word);

   // ----------------
   // Facing a hart: reset and run-control
   interface Get #(Token)         hart0_get_reset_req;
   interface Client #(Bool, Bool) hart0_client_run_halt;
   interface Get #(Bit #(4))      hart0_get_other_req;

   // ----------------
   // Facing Platform: Non-Debug-Module Reset (reset all except DM)
   interface Get #(Token) get_ndm_reset_req;
endinterface

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

(* synthesize *)
module mkDM_Run_Control (DM_Run_Control_IFC);

   Integer verbosity = 0;    // Normally 0; non-zero for debugging

   // ----------------------------------------------------------------
   // NDM Reset

   FIFOF #(Token) f_ndm_reset_reqs <- mkFIFOF;

   // ----------------------------------------------------------------
   // Hart0 run control

   Reg #(Bool) rg_hart0_running <- mkRegU;

   // Reset requests to hart
   FIFOF #(Token) f_hart0_reset_reqs <- mkFIFOF;

   // Run/halt requests to hart and responses
   FIFOF #(Bool)  f_hart0_run_halt_reqs   <- mkFIFOF;
   FIFOF #(Bool)  f_hart0_run_halt_rsps   <- mkFIFOF;

   // Non-standard requests to hart and responses
   // Currently only verbosity
   FIFOF #(Bit #(4)) f_hart0_other_reqs <- mkFIFOF;

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

   Bit #(32) haltregion0 = { 31'h0, pack (! rg_hart0_running) };
   Bit #(32) haltsum     = { 31'h0, pack (! rg_hart0_running) };

   // ----------------------------------------------------------------
   // rg_dmstatus
   // Since we currently support only 1 hart,
   //     'anyXX' = 'allXX'
   //     'allrunning' = NOT 'allhalted'

   Reg#(Bool) rg_dmstatus_allresumeack <- mkRegU;

   Bool dmstatus_allresumeack   = rg_dmstatus_allresumeack;
   Bool dmstatus_anyresumeack   = rg_dmstatus_allresumeack;

   Bool dmstatus_allnonexistent = False;
   Bool dmstatus_anynonexistent = dmstatus_allnonexistent;

   Bool dmstatus_allunavail     = False;
   Bool dmstatus_anyunavail     = dmstatus_allunavail;

   Bool dmstatus_allrunning     = rg_hart0_running;
   Bool dmstatus_anyrunning     = dmstatus_allrunning;

   Bool dmstatus_allhalted      = (! rg_hart0_running);
   Bool dmstatus_anyhalted      = dmstatus_allhalted;

   DM_Word virt_rg_dmstatus = {14'b0,
			       pack (dmstatus_allresumeack),
			       pack (dmstatus_anyresumeack),
			       pack (dmstatus_allnonexistent),
			       pack (dmstatus_anynonexistent),
			       pack (dmstatus_allunavail),
			       pack (dmstatus_anyunavail),
			       pack (dmstatus_allrunning),
			       pack (dmstatus_anyrunning),
			       pack (dmstatus_allhalted),
			       pack (dmstatus_anyhalted),
			       pack (True),                     // authenticated
			       pack (False),                    // authbusy
			       1'b0,
			       pack (False),                    // devtreevalid
			       4'h2};                           // version

   // ----------------------------------------------------------------
   // rg_dmcontrol

   Reg #(Bool)  rg_dmcontrol_haltreq   <- mkRegU;
   // resumereq is a W1 field, no need for a register
   Reg #(Bool)  rg_dmcontrol_hartreset <- mkRegU;
   Reg #(Bool)  rg_dmcontrol_ndmreset  <- mkRegU;
   Reg #(Bool)  rg_dmcontrol_dmactive  <- mkReg (False);

   DM_Word virt_rg_dmcontrol = {2'b0,  // haltreq, resumereq (w-o)
				pack (rg_dmcontrol_hartreset),
				2'b0,
				pack (False),    // hasel
				10'b0,           // hartsel
				14'b0,
				pack (rg_dmcontrol_ndmreset),
				pack (rg_dmcontrol_dmactive)};

   function Action fa_rg_dmcontrol_write (DM_Word dm_word);
      action
	 let haltreq   = fn_dmcontrol_haltreq   (dm_word);
	 let resumereq = fn_dmcontrol_resumereq (dm_word);
	 let hartreset = fn_dmcontrol_hartreset (dm_word);
	 let hasel     = fn_dmcontrol_hasel     (dm_word);
	 let hartsel   = fn_dmcontrol_hartsel   (dm_word);
	 let ndmreset  = fn_dmcontrol_ndmreset  (dm_word);
	 let dmactive  = fn_dmcontrol_dmactive  (dm_word);

	 rg_dmcontrol_haltreq   <= haltreq;
	 rg_dmcontrol_hartreset <= hartreset;
	 rg_dmcontrol_ndmreset  <= ndmreset;
	 rg_dmcontrol_dmactive  <= dmactive;

	 // Debug Module reset
	 if (! dmactive) begin
	    // Reset the DM module itself
	    $display ("DM_Run_Control.write: dmcontrol 0x%08h (dmactive=0): resetting Debug Module",
		      dm_word);

	    // Error-checking
	    if (ndmreset) begin
	       $display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
			 dm_word);
	       $display ("    [1] (ndmreset) and [0] (dmactive) both asserted");
	       $display ("    dmactive has priority; ignoring ndmreset");
	    end
	    if (hartreset) begin
	       $display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
			 dm_word);
	       $display ("    [29] (hartreset) and [0] (dmactive) both asserted");
	       $display ("    dmactive has priority; ignoring hartreset");
	    end

	    // No action here; other rules will fire (see method dmactive, Debug_Module.rl_reset)
	    noAction;
	 end

	 // Platform reset (non-Debug Module)
	 else if (ndmreset) begin
	    $display ("DM_Run_Control.write: dmcontrol 0x%08h: ndmreset=1: resetting platform",
		      dm_word);
	    f_ndm_reset_reqs.enq (?);
	    rg_hart0_running <= True;    // Must be same as run/halt state of CPU after hart_reset!

	    // Error-checking
	    if (hartreset) begin
	       $display ("DM_Run_Control.write: WARNING: in word written to dmcontrol (0x%08h):",
			 dm_word);
	       $display ("    Both ndmreset (bit 1) and hartreset (bit 29) are asserted");
	       $display ("    ndmreset has priority; ignoring hartreset");
	    end
	 end
	 else begin
	    // Deassert platform reset
	    if ((verbosity != 0) && rg_dmcontrol_ndmreset)
	       $display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing ndmreset", dm_word);

	    // Hart reset
	    if (hartreset) begin
	       if (verbosity != 0)
		  $display ("DM_Run_Control.write: dmcontrol 0x%08h: hartreset=1: resetting hart",
			    dm_word);
	       f_hart0_reset_reqs.enq (?);
	       rg_hart0_running <= True;    // Must be same as run/halt state of CPU after hart_reset!
	    end
	    else begin
	       // Deassert hart reset
	       if ((verbosity != 0) && rg_dmcontrol_hartreset)
		  $display ("DM_Run_Control.write: dmcontrol 0x%08h: clearing hartreset", dm_word);

	       if (hasel)
		  $display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: 'hasel' is not supported",
			    dm_word);

	       if (hartsel != 0)
		  $display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: hartsel 0x%0h not supported",
			    dm_word, hartsel);

	       if (haltreq && resumereq) begin
		  $display ("DM_Run_Control.write: ERROR: dmcontrol 0x%08h: haltreq=1 and resumereq=1",
			    dm_word);
		  $display ("    This behavior is 'undefined' in the spec; ignoring");
	       end
	       // Resume hart(s) if not running
	       else if (resumereq && (! rg_hart0_running)) begin
		  f_hart0_run_halt_reqs.enq (True);
		  rg_dmstatus_allresumeack <= False;
		  $display ("DM_Run_Control.write: hart0 resume request");
	       end
	       // Halt hart(s)
	       else if (haltreq && !rg_dmcontrol_haltreq) begin
		  f_hart0_run_halt_reqs.enq (False);
		  $display ("DM_Run_Control.write: hart0 halt request");
	       end
	    end
	 end
      endaction
   endfunction

   // ----------------------------------------------------------------
   // Unimplemented

   // dm_addr_hartinfo
   // dm_addr_hawindowsel
   // dm_addr_hawindow
   // dm_addr_devtreeaddr0..3
   // dm_addr_authdata
   // dm_addr_haltregion1..31

   // ----------------------------------------------------------------
   // rg_verbosity: non-standard

   Reg #(Bit #(4)) rg_verbosity <- mkRegU;

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

   rule rl_hart0_run_rsp;
      let x = f_hart0_run_halt_rsps.first;
      f_hart0_run_halt_rsps.deq;

      rg_hart0_running <= x;
      if (x) begin
	 rg_dmstatus_allresumeack <= True;
	 $display ("DM_Run_Control: hart0 running");
      end
      else begin
	 $display ("DM_Run_Control: hart0 halted");
      end
   endrule

   // ----------------------------------------------------------------
   // INTERFACE

   method Bool dmactive;
      return rg_dmcontrol_dmactive;
   endmethod

   method Action reset;
      f_ndm_reset_reqs.clear;

      rg_hart0_running <= True;    // Must be same as run/halt state of CPU after hart_reset!
      f_hart0_reset_reqs.clear;
      f_hart0_run_halt_reqs.clear;
      f_hart0_run_halt_rsps.clear;

      rg_dmcontrol_haltreq   <= False;
      rg_dmcontrol_hartreset <= False;
      rg_dmcontrol_ndmreset  <= False;
      rg_dmcontrol_dmactive  <= True;    // DM module is now active

      rg_dmstatus_allresumeack <= False;

      rg_verbosity <= 0;

      if (verbosity != 0)
	 $display ("DM_Run_Control: reset");
   endmethod

   // ----------------
   // DMI facing GDB/host

   method ActionValue #(DM_Word) av_read (DM_Addr dm_addr);
      actionvalue
	 DM_Word dm_word = case (dm_addr)
			      dm_addr_dmcontrol:   virt_rg_dmcontrol;
			      dm_addr_dmstatus:    virt_rg_dmstatus;
			      dm_addr_haltsum:     haltsum;
			      dm_addr_haltregion0: haltregion0;
			      dm_addr_verbosity:   extend (rg_verbosity);
			   endcase;

	 if (verbosity != 0)
	    $display ("DM_Run_Control.av_read: [", fshow_dm_addr (dm_addr), "] => 0x%08h", dm_word);

	 return dm_word;
      endactionvalue
   endmethod

   method Action write (DM_Addr dm_addr, DM_Word dm_word);
      action
	 if (verbosity != 0)
	    $display ("DM_Run_Control.write: [", fshow_dm_addr (dm_addr), "] <= 0x%08h", dm_word);

	 case (dm_addr)
	    dm_addr_dmcontrol: fa_rg_dmcontrol_write (dm_word);
	    dm_addr_verbosity: begin
				  rg_verbosity <= truncate (dm_word);
				  f_hart0_other_reqs.enq (truncate (dm_word));
			       end
	    default: noAction;
	 endcase
      endaction
   endmethod

   // ----------------
   // Facing Hart: Reset, Run-control, etc.
   interface Get    hart0_get_reset_req   = toGet (f_hart0_reset_reqs);
   interface Client hart0_client_run_halt = toGPClient (f_hart0_run_halt_reqs, f_hart0_run_halt_rsps);
   interface Get    hart0_get_other_req   = toGet (f_hart0_other_reqs);

   // ----------------
   // Facing Platform: Non-Debug-Module Reset (reset all except DM)
   interface Get get_ndm_reset_req = toGet (f_ndm_reset_reqs);
endmodule

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

endpackage


delete duplicate assignments which caused build failure

// 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 PortalMemory::*;
import Dma::*;

interface PerfRequest;
   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) repeatCount);
   method Action readWord();
   method Action getStateDbg();
endinterface

interface PerfIndication;
   method Action started(Bit#(32) numWords);
   method Action readWordResult(Bit#(32) v);
   method Action done(Bit#(32) dataMismatch);
   method Action rData(Bit#(64) v);
   method Action readReq(Bit#(32) v);
   method Action writeReq(Bit#(32) v);
   method Action writeAck(Bit#(32) v);
   method Action reportStateDbg(Bit#(32) srcGen, Bit#(32) streamRdCnt, Bit#(32) streamWrCnt, Bit#(32) writeInProg, Bit#(32) dataMismatch);
endinterface

module mkPerfRequest#(PerfIndication indication,
			DmaReadServer#(busWidth) dma_stream_read_server,
			DmaWriteServer#(busWidth) dma_stream_write_server,
			DmaReadServer#(busWidth) dma_word_read_server)
   (PerfRequest)
   provisos (Div#(busWidth,8,busWidthBytes),
	     Add#(a__,32,busWidth));

   let busWidthBytes = valueOf(busWidthBytes);
   let busWidthWords = busWidthBytes/4;

   Reg#(Bit#(32))      srcGen <- mkReg(0);
   Reg#(Bit#(32)) wordCnt <- mkReg(0);
   Reg#(Bit#(32)) streamRdCnt <- mkReg(0);
   Reg#(Bit#(32)) streamWrCnt <- mkReg(0);
   Reg#(Bit#(32)) streamAckCnt <- mkReg(0);
   Reg#(Bit#(32)) repeatCnt <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) streamRdOff <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) streamWrOff <- mkReg(0);
   Reg#(DmaPointer)    streamRdPointer <- mkReg(0);
   Reg#(DmaPointer)    streamWrPointer <- mkReg(0);
   Reg#(Bool)               writeInProg <- mkReg(False);
   Reg#(Bool)               iterInProg <- mkReg(False);
   Reg#(Bool)              dataMismatch <- mkReg(False);

   Reg#(Bit#(8)) burstLen <- mkReg(8);
   Reg#(Bit#(DmaOffsetSize)) deltaOffset <- mkReg(8*fromInteger(busWidthBytes));

   rule readReq(streamRdCnt > 0);
      streamRdCnt <= streamRdCnt - extend(burstLen);
      streamRdOff <= streamRdOff + deltaOffset;
      //$display("readReq.put pointer=%h address=%h, burstlen=%h", streamRdPointer, streamRdOff, burstLen);
      dma_stream_read_server.readReq.put(DmaRequest {pointer: streamRdPointer, offset: streamRdOff, burstLen: extend(burstLen), tag: truncate(streamRdOff>>5)});
      //indication.readReq(streamRdCnt);
   endrule

   rule writeReq(streamWrCnt > 0 && !writeInProg);
      writeInProg <= True;
      streamWrCnt <= streamWrCnt-extend(burstLen);
      streamWrOff <= streamWrOff + deltaOffset;
      //$display("writeReq.put pointer=%h address=%h", streamWrPointer, streamWrOff);
      dma_stream_write_server.writeReq.put(DmaRequest {pointer: streamWrPointer, offset: streamWrOff, burstLen: extend(burstLen), tag: truncate(streamWrOff>>5)});
      //indication.writeReq(streamWrCnt);
   endrule

   rule writeAck(writeInProg);
      writeInProg <= False;
      let tag <- dma_stream_write_server.writeDone.get();
      //$display("writeAck: tag=%d", tag);
      streamAckCnt <= streamAckCnt-extend(burstLen);
      //indication.writeAck(streamAckCnt);
      if(streamAckCnt==extend(burstLen))
	 iterInProg <= False;
   endrule

   rule loopback;
      let tagdata <- dma_stream_read_server.readData.get();
      let v = tagdata.data;
      Bool mismatch = False;
      //for (Integer i = 0; i < busWidthWords; i = i+1)
	// mismatch = mismatch || (v[31+i*32:i*32] != (srcGen + fromInteger(i)));
      //dataMismatch <= dataMismatch || mismatch;
      dma_stream_write_server.writeData.put(tagdata);
      srcGen <= srcGen+fromInteger(busWidthWords);
      //$display("loopback %h", tagdata.data);
      // indication.rData(v);
   endrule

   rule readWordResp;
      let tagdata <- dma_word_read_server.readData.get;
      indication.readWordResult(truncate(tagdata.data));
   endrule

   rule startIteration((iterInProg == False) && (repeatCnt > 0));
      streamRdOff <= 0;
      streamWrOff <= 0;
      streamRdCnt <= wordCnt;
      streamWrCnt <= wordCnt;
      streamAckCnt <= wordCnt;
      iterInProg <= True;
      repeatCnt <= repeatCnt - 1;
   endrule

   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) repeatCount) if (streamRdCnt == 0 && streamWrCnt == 0);
      //$display("startCopy wrPointer=%h rdPointer=%h numWords=%d", wrPointer, rdPointer, numWords);

      streamWrPointer <= wrPointer;
      streamRdPointer <= rdPointer;
      wordCnt <= numWords >> 1;
      repeatCnt <= repeatCount;
      indication.started(numWords);
   endmethod

   method Action readWord();
      dma_word_read_server.readReq.put(DmaRequest {pointer: streamWrPointer, offset: 0, burstLen: 1, tag: 1});
   endmethod

   method Action getStateDbg();
      indication.reportStateDbg(srcGen, streamRdCnt, streamWrCnt, writeInProg ? 32'd1 : 32'd0, dataMismatch  ? 32'd1 : 32'd0);
   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 Vector::*;
import FIFOF::*;
import GetPutF::*;

import PortalMemory::*;
import Dma::*;

interface PerfRequest;
   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) repeatCount);
   method Action readWord();
   method Action getStateDbg();
endinterface

interface PerfIndication;
   method Action started(Bit#(32) numWords);
   method Action readWordResult(Bit#(32) v);
   method Action done(Bit#(32) dataMismatch);
   method Action rData(Bit#(64) v);
   method Action readReq(Bit#(32) v);
   method Action writeReq(Bit#(32) v);
   method Action writeAck(Bit#(32) v);
   method Action reportStateDbg(Bit#(32) srcGen, Bit#(32) streamRdCnt, Bit#(32) streamWrCnt, Bit#(32) writeInProg, Bit#(32) dataMismatch);
endinterface

module mkPerfRequest#(PerfIndication indication,
			DmaReadServer#(busWidth) dma_stream_read_server,
			DmaWriteServer#(busWidth) dma_stream_write_server,
			DmaReadServer#(busWidth) dma_word_read_server)
   (PerfRequest)
   provisos (Div#(busWidth,8,busWidthBytes),
	     Add#(a__,32,busWidth));

   let busWidthBytes = valueOf(busWidthBytes);
   let busWidthWords = busWidthBytes/4;

   Reg#(Bit#(32))      srcGen <- mkReg(0);
   Reg#(Bit#(32)) wordCnt <- mkReg(0);
   Reg#(Bit#(32)) streamRdCnt <- mkReg(0);
   Reg#(Bit#(32)) streamWrCnt <- mkReg(0);
   Reg#(Bit#(32)) streamAckCnt <- mkReg(0);
   Reg#(Bit#(32)) repeatCnt <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) streamRdOff <- mkReg(0);
   Reg#(Bit#(DmaOffsetSize)) streamWrOff <- mkReg(0);
   Reg#(DmaPointer)    streamRdPointer <- mkReg(0);
   Reg#(DmaPointer)    streamWrPointer <- mkReg(0);
   Reg#(Bool)               writeInProg <- mkReg(False);
   Reg#(Bool)               iterInProg <- mkReg(False);
   Reg#(Bool)              dataMismatch <- mkReg(False);

   Reg#(Bit#(8)) burstLen <- mkReg(8);
   Reg#(Bit#(DmaOffsetSize)) deltaOffset <- mkReg(8*fromInteger(busWidthBytes));

   rule readReq(streamRdCnt > 0);
      streamRdCnt <= streamRdCnt - extend(burstLen);
      streamRdOff <= streamRdOff + deltaOffset;
      //$display("readReq.put pointer=%h address=%h, burstlen=%h", streamRdPointer, streamRdOff, burstLen);
      dma_stream_read_server.readReq.put(DmaRequest {pointer: streamRdPointer, offset: streamRdOff, burstLen: extend(burstLen), tag: truncate(streamRdOff>>5)});
      //indication.readReq(streamRdCnt);
   endrule

   rule writeReq(streamWrCnt > 0 && !writeInProg);
      writeInProg <= True;
      streamWrCnt <= streamWrCnt-extend(burstLen);
      streamWrOff <= streamWrOff + deltaOffset;
      //$display("writeReq.put pointer=%h address=%h", streamWrPointer, streamWrOff);
      dma_stream_write_server.writeReq.put(DmaRequest {pointer: streamWrPointer, offset: streamWrOff, burstLen: extend(burstLen), tag: truncate(streamWrOff>>5)});
      //indication.writeReq(streamWrCnt);
   endrule

   rule writeAck(writeInProg);
      writeInProg <= False;
      let tag <- dma_stream_write_server.writeDone.get();
      //$display("writeAck: tag=%d", tag);
      streamAckCnt <= streamAckCnt-extend(burstLen);
      //indication.writeAck(streamAckCnt);
      if(streamAckCnt==extend(burstLen))
	 iterInProg <= False;
   endrule

   rule loopback;
      let tagdata <- dma_stream_read_server.readData.get();
      let v = tagdata.data;
      Bool mismatch = False;
      //for (Integer i = 0; i < busWidthWords; i = i+1)
	// mismatch = mismatch || (v[31+i*32:i*32] != (srcGen + fromInteger(i)));
      //dataMismatch <= dataMismatch || mismatch;
      dma_stream_write_server.writeData.put(tagdata);
      srcGen <= srcGen+fromInteger(busWidthWords);
      //$display("loopback %h", tagdata.data);
      // indication.rData(v);
   endrule

   rule readWordResp;
      let tagdata <- dma_word_read_server.readData.get;
      indication.readWordResult(truncate(tagdata.data));
   endrule

   rule startIteration((iterInProg == False) && (repeatCnt > 0));
      streamRdOff <= 0;
      streamWrOff <= 0;
      streamRdCnt <= wordCnt;
      streamWrCnt <= wordCnt;
      streamAckCnt <= wordCnt;
      iterInProg <= True;
      repeatCnt <= repeatCnt - 1;
   endrule

   method Action startCopy(Bit#(32) wrPointer, Bit#(32) rdPointer, Bit#(32) numWords, Bit#(32) repeatCount) if (streamRdCnt == 0 && streamWrCnt == 0);
      //$display("startCopy wrPointer=%h rdPointer=%h numWords=%d", wrPointer, rdPointer, numWords);

      streamWrPointer <= wrPointer;
      streamRdPointer <= rdPointer;
      streamWrPointer <= wrPointer;
      streamRdPointer <= rdPointer;
      wordCnt <= numWords >> 1;
      repeatCnt <= repeatCount;
      indication.started(numWords);
   endmethod

   method Action readWord();
      dma_word_read_server.readReq.put(DmaRequest {pointer: streamWrPointer, offset: 0, burstLen: 1, tag: 1});
   endmethod

   method Action getStateDbg();
      indication.reportStateDbg(srcGen, streamRdCnt, streamWrCnt, writeInProg ? 32'd1 : 32'd0, dataMismatch  ? 32'd1 : 32'd0);
   endmethod

endmodule


use correct tagged types in DMA interface

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

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

   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(cmdRing.bufferlast);
	 cmdRing.pop();
      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())
	    for (ii <= 1; ii < 8; ii <= ii + 1)
	       action
		  status_write_chan.writeReq.put(statusRing.expBufferFirst);
		  status_write_chan.writeData.put(copyEngine.get());
		  statusRing.push(8);
	       endaction
	 if (statusRing.notFull() && echoEngine.response.notEmpty())
	    for (ii <= 1; ii < 8; ii <= ii + 1)
	       action
		  status_write_chan.writeReq.put(statusRing.expBufferFirst);
		  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


Implement button edge detection

Implement button edge detection

import AvalonSlave::*;
import InterruptSender::*;

typedef 3  AvalonAddrSize;
typedef 32 AvalonDataSize;

interface AcqSys;
	(* prefix="" *)
	interface InterruptSenderWires irqWires;
	(* prefix="" *)
	interface AvalonSlaveWires#(AvalonAddrSize, AvalonDataSize) avalonWires;
	(* prefix="", always_ready, always_enabled *)
	method Action setButton((*port="button"*)Bit#(1) x);
endinterface

(* synthesize, clock_prefix="clk", reset_prefix="reset_n" *)
module mkAcqSys(AcqSys);
	InterruptSender irq <- mkInterruptSender;
	AvalonSlave#(AvalonAddrSize, AvalonDataSize) avalon <- mkAvalonSlave;

	Reg#(Bit#(1)) btnreg <- mkReg(1);
	Reg#(Bit#(1)) btnprevreg <- mkReg(1);

	rule handle_cmd;
		let cmd <- avalon.busClient.request.get;
		case (cmd) matches
			tagged AvalonRequest{addr: 0, data: .x, command: Write}:
				irq.enabled <= x != 0;
			tagged AvalonRequest{addr: 1, data: .*, command: Write}:
				irq.clear;
		endcase
	endrule

	rule edge_detect (btnprevreg == 1 && btnreg == 0);
		irq.send;
	endrule

	interface irqWires = irq.irqWires;
	interface avalonWires = avalon.slaveWires;

	method Action setButton(Bit#(1) x);
		btnreg <= x;
		btnprevreg <= btnreg;
	endmethod
endmodule

import AvalonSlave::*;
import InterruptSender::*;

typedef 3  AvalonAddrSize;
typedef 32 AvalonDataSize;

interface AcqSys;
	(* prefix="" *)
	interface InterruptSenderWires irqWires;
	(* prefix="" *)
	interface AvalonSlaveWires#(AvalonAddrSize, AvalonDataSize) avalonWires;
	(* always_ready, prefix="", enable="button" *)
	method Action button;
endinterface

(* synthesize, clock_prefix="clk", reset_prefix="reset_n" *)
module mkAcqSys(AcqSys);
	InterruptSender irq <- mkInterruptSender;
	AvalonSlave#(AvalonAddrSize, AvalonDataSize) avalon <- mkAvalonSlave;

	rule handle_cmd;
		let cmd <- avalon.busClient.request.get;
		case (cmd) matches
			tagged AvalonRequest{addr: 0, data: .x, command: Write}:
				irq.enabled <= x != 0;
			tagged AvalonRequest{addr: 1, data: .*, command: Write}:
				irq.clear;
		endcase
	endrule

	interface irqWires = irq.irqWires;
	interface avalonWires = avalon.slaveWires;

	method Action button = irq.send;
endmodule


reduce verbosity of Dsp48E1

reduce verbosity of Dsp48E1

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

interface Dsp48E1;
   method Bool     notEmpty();
   method Bit#(48) p();
   method Action deq();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action last(Bit#(1) v);
endinterface

`ifndef BSIM
(* always_ready, always_enabled *)
interface PRIM_DSP48E1;
   method Bit#(48) p();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action acin(Bit#(30) v);
   method Action bcin(Bit#(18) v);
   method Action carrycascin(Bit#(1) v);
   method Action carryin(Bit#(1) v);
   method Action multsignin(Bit#(1) v);
   method Action pcin(Bit#(48) v);

   method Action cea1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage AREG
   method Action cea2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage AREG
   method Action cead(Bit#(1) en);		// 1-bit input: Clock enable input for ADREG
   method Action ceb1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage BREG
   method Action ceb2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage BREG
   method Action cealumode(Bit#(1) en);		// 1-bit input: Clock enable input for ALUMODE
   method Action cec(Bit#(1) en);		// 1-bit input: Clock enable input for CREG
   method Action cecarryin(Bit#(1) en);		// 1-bit input: Clock enable input for CARRYINREG
   method Action cectrl(Bit#(1) en);		// 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
   method Action ced(Bit#(1) en);		// 1-bit input: Clock enable input for DREG
   method Action ceinmode(Bit#(1) en);		// 1-bit input: Clock enable input for INMODEREG
   method Action cem(Bit#(1) en);		// 1-bit input: Clock enable input for MREG
   method Action cep(Bit#(1) en);		// 1-bit input: Clock enable input for PREG
endinterface

import "BVI" DSP48E1 =
module vmkDSP48E1(PRIM_DSP48E1);
   let currentClock <- exposeCurrentClock;
   let currentReset <- exposeCurrentReset;
`ifndef BSV_POSITIVE_RESET
   let invertedReset <- mkResetInverter(currentReset);
   let dspReset <- mkSyncReset(10, invertedReset, currentClock);
`else
   let dspReset = currentReset;
`endif
   default_clock clk(CLK);

   default_reset rsta(RSTA) = dspReset;
   input_reset rstb(RSTB) = dspReset;
   input_reset rstc(RSTC) = dspReset;
   input_reset rstd(RSTD) = dspReset;
   input_reset rstallcarryin(RSTALLCARRYIN) = dspReset;
   input_reset rstalumode(RSTALUMODE) = dspReset;
   input_reset rstctrl(RSTCTRL) = dspReset;
   input_reset rstinmode(RSTINMODE) = dspReset;
   input_reset rstm(RSTM) = dspReset;
   input_reset rstp(RSTP) = dspReset;

   method P p();
   method alumode(ALUMODE) enable ((*inhigh*)EN_alumode);
   method carryinsel(CARRYINSEL) enable ((*inhigh*)EN_carryinsel);
   method inmode(INMODE) enable ((*inhigh*)EN_inmode);
   method opmode(OPMODE) enable ((*inhigh*)EN_opmode);
   method a(A) enable ((*inhigh*)EN_a);
   method b(B) enable ((*inhigh*)EN_b);
   method c(C) enable ((*inhigh*)EN_c);
   method d(D) enable ((*inhigh*)EN_d);
   method acin(ACIN) enable ((*inhigh*)EN_acin);
   method bcin(BCIN) enable ((*inhigh*)EN_bcin);
   method carrycascin(CARRYCASCIN) enable ((*inhigh*)EN_carrycascin);
   method carryin(CARRYIN) enable ((*inhigh*)EN_carryin);
   method multsignin(MULTSIGNIN) enable ((*inhigh*)EN_multsignin);
   method pcin(PCIN) enable ((*inhigh*)EN_pcin);

   method cea1(CEA1) enable ((*inhigh*)EN_cea1);
   method cea2(CEA2) enable ((*inhigh*)EN_cea2);
   method cead(CEAD) enable ((*inhigh*)EN_cead);
   method ceb1(CEB1) enable ((*inhigh*)EN_ceb1);
   method ceb2(CEB2) enable ((*inhigh*)EN_ceb2);
   method cealumode(CEALUMODE) enable ((*inhigh*)EN_cealumode);
   method cec(CEC) enable ((*inhigh*)EN_cec);
   method cecarryin(CECARRYIN) enable ((*inhigh*)EN_cecarryin);
   method cectrl(CECTRL) enable ((*inhigh*)EN_cectrl);
   method ced(CED) enable ((*inhigh*)EN_ced);
   method ceinmode(CEINMODE) enable ((*inhigh*)EN_ceinmode);
   method cem(CEM) enable ((*inhigh*)EN_cem);
   method cep(CEP) enable ((*inhigh*)EN_cep);
   schedule (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p)
      CF (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p);
endmodule

(* synthesize *)
module mkDsp48E1(Dsp48E1);
   let dsp <- vmkDSP48E1();
   let defaultReset <- exposeCurrentReset;
   let optionalReset = defaultReset; // noReset
   Wire#(Bit#(4)) alumodeWire <- mkDWire(0);
   Reg#(Bit#(4)) alumodeReg <- mkReg(0);
   Wire#(Bit#(3)) carryinselWire <- mkDWire(0);
   Wire#(Bit#(5)) inmodeWire <- mkDWire(0);
   Wire#(Bit#(7)) opmodeWire <- mkDWire(7'h20);
   Reg#(Bit#(7)) opmode1Reg <- mkReg(0);
   Reg#(Bit#(7)) opmode2Reg <- mkReg(0);
   Reg#(Bit#(7)) opmode3Reg <- mkReg(0);
   Reg#(Bit#(7)) opmode4Reg <- mkReg(0);

   Wire#(Bit#(30)) aWire <- mkDWire(0);
   Wire#(Bit#(18)) bWire <- mkDWire(0);
   Wire#(Bit#(48)) cWire <- mkDWire(0);
   Wire#(Bit#(25)) dWire <- mkDWire(0);
   Reg#(Bit#(48))  c1Reg <- mkReg(0);
   Reg#(Bit#(48))  c2Reg <- mkReg(0);
   Reg#(Bit#(48))  c3Reg <- mkReg(0);

   Wire#(Bit#(1)) ce1Wire <- mkDWire(0);
   Reg#(Bit#(1)) ce2Reg <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1)) cepReg <- mkReg(0, reset_by optionalReset);
   Wire#(Bit#(1)) lastWire <- mkDWire(0);
   Reg#(Bit#(1))  last1Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last2Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last3Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last4Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last5Reg  <- mkReg(0, reset_by optionalReset);

   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule cyclesRule;
      cycles <= cycles+1;
   endrule

   rule clock_enable_and_reset;
      ce2Reg <= ce1Wire;
      cepReg <= ce2Reg;

      last1Reg <= lastWire;
      last2Reg <= last1Reg;
      last3Reg <= last2Reg;
      last4Reg <= last3Reg;
      last5Reg <= last4Reg;

      dsp.cea1(1); // (ce1Wire);
      dsp.cea2(1); // (ce2Reg);
      dsp.cead(1);
      dsp.ceb1(1); // (ce1Wire);
      dsp.ceb2(1); // (ce2Reg);
      dsp.cealumode(1); // (ce1Wire);
      dsp.cec(1);
      dsp.cecarryin(1);
      dsp.cectrl(1);
      dsp.ced(1);
      dsp.ceinmode(1);
      dsp.cem(1);
      dsp.cep(1); // (cepReg);

   endrule

   rule driveInputs;
      opmode1Reg <= opmodeWire;
      opmode2Reg <= opmode1Reg;
      opmode3Reg <= opmode2Reg;
      opmode4Reg <= opmode3Reg;

      alumodeReg <= alumodeWire;

      c1Reg <= cWire;
      c2Reg <= c1Reg;
      c3Reg <= c2Reg;

      if (lastWire == 1 || last1Reg == 1 || last2Reg == 1 || last3Reg == 1 || last4Reg == 1 || last5Reg == 1)
	 $display("%d: a=%h b=%h c=%h p=%h", cycles, aWire, bWire, c3Reg, dsp.p());

      dsp.alumode(alumodeReg);
      dsp.carryinsel(carryinselWire);
      dsp.inmode(inmodeWire);
      dsp.opmode(opmode1Reg);
      dsp.a(aWire);
      dsp.b(bWire);
      dsp.c(c1Reg);
      //dsp.d(dWire);

      dsp.acin(0);
      dsp.bcin(0);
      dsp.carrycascin(0);
      dsp.carryin(0);
      dsp.pcin(0);
   endrule

   method Action alumode(Bit#(4) v);
      alumodeWire <= v;
   endmethod
   method Action carryinsel(Bit#(3) v);
      carryinselWire <= v;
   endmethod
   method Action inmode(Bit#(5) v);
      inmodeWire <= v;
   endmethod
   method Action opmode(Bit#(7) v);
      opmodeWire <= v;
   endmethod
   method Action a(Bit#(30) v);
      ce1Wire <= 1;
      aWire <= v;
   endmethod
   method Action b(Bit#(18) v);
      bWire <= v;
   endmethod
   method Action c(Bit#(48) v);
      cWire <= v;
   endmethod
   method Action d(Bit#(25) v);
      dsp.d(v);
   endmethod
   method Bool notEmpty();
      return last5Reg == 1;
   endmethod
   method Bit#(48) p() if (last5Reg == 1);
      return dsp.p();
   endmethod
   method Action deq() if (last5Reg == 1);
   endmethod
   method Action last(Bit#(1) v);
      lastWire <= v;
   endmethod
endmodule
`else
module mkDsp48E1(Dsp48E1);
   let defaultReset <- exposeCurrentReset;
   let optionalReset = defaultReset; // noReset

   Reg#(Bit#(48)) accumReg <- mkReg(0);
   FIFO#(Bool) lastFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(7)) opmodeFifo <- mkSizedFIFO(3);
   FIFOF#(Bit#(48)) pFifo <- mkSizedFIFOF(3);
   FIFO#(Bit#(30)) aFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(18)) bFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(48)) abFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(48)) cFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(25)) dFifo <- mkSizedFIFO(3);

   rule prod;
      let a <- toGet(aFifo).get();
      let b <- toGet(bFifo).get();
      abFifo.enq(extend(a)*extend(b));
   endrule
   rule accum;
      let last <- toGet(lastFifo).get();
      let opmode <- toGet(opmodeFifo).get();
      let ab <- toGet(abFifo).get();
      let c <- toGet(cFifo).get();
      let d <- toGet(dFifo).get();

      let accum = accumReg;
      if (opmode == 7'h05)
	 accum = 0;
      if (opmode != 0)
	 accum = accum + ab;
      accumReg <= accum;
      if (last)
	 pFifo.enq(accum);
   endrule

   method Action alumode(Bit#(4) v);
   endmethod
   method Action carryinsel(Bit#(3) v);
   endmethod
   method Action inmode(Bit#(5) v);
   endmethod
   method Action opmode(Bit#(7) v);
      opmodeFifo.enq(v);
   endmethod
   method Action a(Bit#(30) v);
      aFifo.enq(v);
   endmethod
   method Action b(Bit#(18) v);
      bFifo.enq(v);
   endmethod
   method Action c(Bit#(48) v);
      cFifo.enq(v);
   endmethod
   method Action d(Bit#(25) v);
      dFifo.enq(v);
   endmethod
   method Bool notEmpty();
      return pFifo.notEmpty();
   endmethod
   method Action last(Bit#(1) v);
      lastFifo.enq(unpack(v));
   endmethod

   method Bit#(48) p() if (pFifo.notEmpty());
      return pFifo.first;
   endmethod
   method Action deq();
      pFifo.deq();
   endmethod
endmodule
`endif

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

interface Dsp48E1;
   method Bool     notEmpty();
   method Bit#(48) p();
   method Action deq();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action last(Bit#(1) v);
endinterface

`ifndef BSIM
(* always_ready, always_enabled *)
interface PRIM_DSP48E1;
   method Bit#(48) p();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action acin(Bit#(30) v);
   method Action bcin(Bit#(18) v);
   method Action carrycascin(Bit#(1) v);
   method Action carryin(Bit#(1) v);
   method Action multsignin(Bit#(1) v);
   method Action pcin(Bit#(48) v);

   method Action cea1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage AREG
   method Action cea2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage AREG
   method Action cead(Bit#(1) en);		// 1-bit input: Clock enable input for ADREG
   method Action ceb1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage BREG
   method Action ceb2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage BREG
   method Action cealumode(Bit#(1) en);		// 1-bit input: Clock enable input for ALUMODE
   method Action cec(Bit#(1) en);		// 1-bit input: Clock enable input for CREG
   method Action cecarryin(Bit#(1) en);		// 1-bit input: Clock enable input for CARRYINREG
   method Action cectrl(Bit#(1) en);		// 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
   method Action ced(Bit#(1) en);		// 1-bit input: Clock enable input for DREG
   method Action ceinmode(Bit#(1) en);		// 1-bit input: Clock enable input for INMODEREG
   method Action cem(Bit#(1) en);		// 1-bit input: Clock enable input for MREG
   method Action cep(Bit#(1) en);		// 1-bit input: Clock enable input for PREG
endinterface

import "BVI" DSP48E1 =
module vmkDSP48E1(PRIM_DSP48E1);
   let currentClock <- exposeCurrentClock;
   let currentReset <- exposeCurrentReset;
`ifndef BSV_POSITIVE_RESET
   let invertedReset <- mkResetInverter(currentReset);
   let dspReset <- mkSyncReset(10, invertedReset, currentClock);
`else
   let dspReset = currentReset;
`endif
   default_clock clk(CLK);

   default_reset rsta(RSTA) = dspReset;
   input_reset rstb(RSTB) = dspReset;
   input_reset rstc(RSTC) = dspReset;
   input_reset rstd(RSTD) = dspReset;
   input_reset rstallcarryin(RSTALLCARRYIN) = dspReset;
   input_reset rstalumode(RSTALUMODE) = dspReset;
   input_reset rstctrl(RSTCTRL) = dspReset;
   input_reset rstinmode(RSTINMODE) = dspReset;
   input_reset rstm(RSTM) = dspReset;
   input_reset rstp(RSTP) = dspReset;

   method P p();
   method alumode(ALUMODE) enable ((*inhigh*)EN_alumode);
   method carryinsel(CARRYINSEL) enable ((*inhigh*)EN_carryinsel);
   method inmode(INMODE) enable ((*inhigh*)EN_inmode);
   method opmode(OPMODE) enable ((*inhigh*)EN_opmode);
   method a(A) enable ((*inhigh*)EN_a);
   method b(B) enable ((*inhigh*)EN_b);
   method c(C) enable ((*inhigh*)EN_c);
   method d(D) enable ((*inhigh*)EN_d);
   method acin(ACIN) enable ((*inhigh*)EN_acin);
   method bcin(BCIN) enable ((*inhigh*)EN_bcin);
   method carrycascin(CARRYCASCIN) enable ((*inhigh*)EN_carrycascin);
   method carryin(CARRYIN) enable ((*inhigh*)EN_carryin);
   method multsignin(MULTSIGNIN) enable ((*inhigh*)EN_multsignin);
   method pcin(PCIN) enable ((*inhigh*)EN_pcin);

   method cea1(CEA1) enable ((*inhigh*)EN_cea1);
   method cea2(CEA2) enable ((*inhigh*)EN_cea2);
   method cead(CEAD) enable ((*inhigh*)EN_cead);
   method ceb1(CEB1) enable ((*inhigh*)EN_ceb1);
   method ceb2(CEB2) enable ((*inhigh*)EN_ceb2);
   method cealumode(CEALUMODE) enable ((*inhigh*)EN_cealumode);
   method cec(CEC) enable ((*inhigh*)EN_cec);
   method cecarryin(CECARRYIN) enable ((*inhigh*)EN_cecarryin);
   method cectrl(CECTRL) enable ((*inhigh*)EN_cectrl);
   method ced(CED) enable ((*inhigh*)EN_ced);
   method ceinmode(CEINMODE) enable ((*inhigh*)EN_ceinmode);
   method cem(CEM) enable ((*inhigh*)EN_cem);
   method cep(CEP) enable ((*inhigh*)EN_cep);
   schedule (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p)
      CF (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p);
endmodule

(* synthesize *)
module mkDsp48E1(Dsp48E1);
   let dsp <- vmkDSP48E1();
   let defaultReset <- exposeCurrentReset;
   let optionalReset = defaultReset; // noReset
   Wire#(Bit#(4)) alumodeWire <- mkDWire(0);
   Reg#(Bit#(4)) alumodeReg <- mkReg(0);
   Wire#(Bit#(3)) carryinselWire <- mkDWire(0);
   Wire#(Bit#(5)) inmodeWire <- mkDWire(0);
   Wire#(Bit#(7)) opmodeWire <- mkDWire(7'h20);
   Reg#(Bit#(7)) opmode1Reg <- mkReg(0);
   Reg#(Bit#(7)) opmode2Reg <- mkReg(0);
   Reg#(Bit#(7)) opmode3Reg <- mkReg(0);
   Reg#(Bit#(7)) opmode4Reg <- mkReg(0);

   Wire#(Bit#(30)) aWire <- mkDWire(0);
   Wire#(Bit#(18)) bWire <- mkDWire(0);
   Wire#(Bit#(48)) cWire <- mkDWire(0);
   Wire#(Bit#(25)) dWire <- mkDWire(0);
   Reg#(Bit#(48))  c1Reg <- mkReg(0);
   Reg#(Bit#(48))  c2Reg <- mkReg(0);
   Reg#(Bit#(48))  c3Reg <- mkReg(0);

   Wire#(Bit#(1)) ce1Wire <- mkDWire(0);
   Reg#(Bit#(1)) ce2Reg <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1)) cepReg <- mkReg(0, reset_by optionalReset);
   Wire#(Bit#(1)) lastWire <- mkDWire(0);
   Reg#(Bit#(1))  last1Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last2Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last3Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last4Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last5Reg  <- mkReg(0, reset_by optionalReset);

   Reg#(Bit#(32)) cycles <- mkReg(0);
   rule cyclesRule;
      cycles <= cycles+1;
   endrule

   rule clock_enable_and_reset;
      ce2Reg <= ce1Wire;
      cepReg <= ce2Reg;

      last1Reg <= lastWire;
      last2Reg <= last1Reg;
      last3Reg <= last2Reg;
      last4Reg <= last3Reg;
      last5Reg <= last4Reg;

      dsp.cea1(1); // (ce1Wire);
      dsp.cea2(1); // (ce2Reg);
      dsp.cead(1);
      dsp.ceb1(1); // (ce1Wire);
      dsp.ceb2(1); // (ce2Reg);
      dsp.cealumode(1); // (ce1Wire);
      dsp.cec(1);
      dsp.cecarryin(1);
      dsp.cectrl(1);
      dsp.ced(1);
      dsp.ceinmode(1);
      dsp.cem(1);
      dsp.cep(1); // (cepReg);

   endrule

   rule driveInputs;
      opmode1Reg <= opmodeWire;
      opmode2Reg <= opmode1Reg;
      opmode3Reg <= opmode2Reg;
      opmode4Reg <= opmode3Reg;

      alumodeReg <= alumodeWire;

      c1Reg <= cWire;
      c2Reg <= c1Reg;
      c3Reg <= c2Reg;

      //if (lastWire == 1 || last1Reg == 1 || last2Reg == 1 || last3Reg == 1 || last4Reg == 1 || last5Reg == 1)
	 $display("%d: a=%h b=%h c=%h p=%h", cycles, aWire, bWire, c3Reg, dsp.p());

      dsp.alumode(alumodeReg);
      dsp.carryinsel(carryinselWire);
      dsp.inmode(inmodeWire);
      dsp.opmode(opmode1Reg);
      dsp.a(aWire);
      dsp.b(bWire);
      dsp.c(c1Reg);
      //dsp.d(dWire);

      dsp.acin(0);
      dsp.bcin(0);
      dsp.carrycascin(0);
      dsp.carryin(0);
      dsp.pcin(0);
   endrule

   method Action alumode(Bit#(4) v);
      alumodeWire <= v;
   endmethod
   method Action carryinsel(Bit#(3) v);
      carryinselWire <= v;
   endmethod
   method Action inmode(Bit#(5) v);
      inmodeWire <= v;
   endmethod
   method Action opmode(Bit#(7) v);
      opmodeWire <= v;
   endmethod
   method Action a(Bit#(30) v);
      ce1Wire <= 1;
      aWire <= v;
   endmethod
   method Action b(Bit#(18) v);
      bWire <= v;
   endmethod
   method Action c(Bit#(48) v);
      cWire <= v;
   endmethod
   method Action d(Bit#(25) v);
      dsp.d(v);
   endmethod
   method Bool notEmpty();
      return last5Reg == 1;
   endmethod
   method Bit#(48) p() if (last5Reg == 1);
      return dsp.p();
   endmethod
   method Action deq() if (last5Reg == 1);
   endmethod
   method Action last(Bit#(1) v);
      lastWire <= v;
   endmethod
endmodule
`else
module mkDsp48E1(Dsp48E1);
   let defaultReset <- exposeCurrentReset;
   let optionalReset = defaultReset; // noReset

   Reg#(Bit#(48)) accumReg <- mkReg(0);
   FIFO#(Bool) lastFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(7)) opmodeFifo <- mkSizedFIFO(3);
   FIFOF#(Bit#(48)) pFifo <- mkSizedFIFOF(3);
   FIFO#(Bit#(30)) aFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(18)) bFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(48)) abFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(48)) cFifo <- mkSizedFIFO(3);
   FIFO#(Bit#(25)) dFifo <- mkSizedFIFO(3);

   rule prod;
      let a <- toGet(aFifo).get();
      let b <- toGet(bFifo).get();
      abFifo.enq(extend(a)*extend(b));
   endrule
   rule accum;
      let last <- toGet(lastFifo).get();
      let opmode <- toGet(opmodeFifo).get();
      let ab <- toGet(abFifo).get();
      let c <- toGet(cFifo).get();
      let d <- toGet(dFifo).get();

      let accum = accumReg;
      if (opmode == 7'h05)
	 accum = 0;
      if (opmode != 0)
	 accum = accum + ab;
      accumReg <= accum;
      if (last)
	 pFifo.enq(accum);
   endrule

   method Action alumode(Bit#(4) v);
   endmethod
   method Action carryinsel(Bit#(3) v);
   endmethod
   method Action inmode(Bit#(5) v);
   endmethod
   method Action opmode(Bit#(7) v);
      opmodeFifo.enq(v);
   endmethod
   method Action a(Bit#(30) v);
      aFifo.enq(v);
   endmethod
   method Action b(Bit#(18) v);
      bFifo.enq(v);
   endmethod
   method Action c(Bit#(48) v);
      cFifo.enq(v);
   endmethod
   method Action d(Bit#(25) v);
      dFifo.enq(v);
   endmethod
   method Bool notEmpty();
      return pFifo.notEmpty();
   endmethod
   method Action last(Bit#(1) v);
      lastFifo.enq(unpack(v));
   endmethod

   method Bit#(48) p() if (pFifo.notEmpty());
      return pFifo.first;
   endmethod
   method Action deq();
      pFifo.deq();
   endmethod
endmodule
`endif


fixed directory read state machine

fixed directory read state machine

// Copyright (c) 2015 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 FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemTypes          :: *;
import HostInterface     :: *;
import CtrlMux           :: *;
import ClientServer      :: *;
import PCIE              :: *;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimTop;
   method Bit#(1) rd();
   method ActionValue#(Bit#(32)) directoryEntry();
   method Action read(Bit#(32) addr);
   method ActionValue#(Bit#(32)) readData();
   method Action write(Bit#(32) addr, Bit#(32) data);

   interface Clock singleClock;
   interface Reset singleReset;
endinterface

module  mkXsimTop(XsimTop);
   //let divider <- mkClockDivider(2);
   Clock derivedClock <- exposeCurrentClock; //= divider.fastClock;
   Clock single_clock = derivedClock; //divider.slowClock;
   Reset derivedReset <- exposeCurrentReset;
   //let sr <- mkReset(2, True, single_clock);
   Reset single_reset = derivedReset; //sr.new_rst;

   XsimHost host <- mkXsimHost(clocked_by single_clock, reset_by single_reset, derivedClock, derivedReset);
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`endif
       clocked_by single_clock, reset_by single_reset);
   //mapM(uncurry(mkConnection),zip(top.masters, host.mem_servers), clocked_by single_clock, reset_by single_reset);

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule int_rule;
      //interruptLevel(truncate(pack(intr_mux)));
   endrule

   Reg#(Bool) readingDirectory <- mkReg(True);
   Reg#(Bool) token <- mkReg(True);
   Reg#(Bit#(8)) portalNumber <- mkReg(0);
   Reg#(Bit#(8)) offset <- mkReg(8'h10);
   Reg#(Bit#(32)) idReg <- mkReg(0);
   FIFO#(Bit#(32)) directoryFifo <- mkFIFO();
   rule readDirectory if (readingDirectory && portalNumber < 16 && token);
      let o = offset;
      let pn = portalNumber;
      top.slave.read_server.readReq.put(PhysMemRequest { addr: (extend(portalNumber) << 16) | extend(offset), burstLen: 4, tag: (o == 8'h10) ? 7 : 9});
      if (offset == 8'h14) begin
	 o = 8'h10;
	 pn = pn + 1;
      end
      else begin
	 o = o + 4;
      end
      offset <= o;
      portalNumber <= pn;
      token <= False;
   endrule
   rule directoryValue if (readingDirectory && !token);
      let memData <- top.slave.read_server.readData.get();

      let t = token;
      if (memData.tag == 7) begin
	 idReg <= memData.data;
	 t = True;
      end
      else begin
	 directoryFifo.enq((extend(memData.data[0]) << 31) | idReg);
	 // if this is not the last one, then read the next portal
	 t = (memData.data[0] == 0);
      end
      token <= t;
   endrule

   method Bit#(1) rd();
      return readingDirectory ? 1 : 0;
   endmethod
   method ActionValue#(Bit#(32)) directoryEntry() if (readingDirectory);
      let v <- toGet(directoryFifo).get();
      if (v[31] == 1)
	 readingDirectory <= False;
      return v;
   endmethod

   method Action read(Bit#(32) addr) if (!readingDirectory);
      $display("read addr=%h", addr);
      top.slave.read_server.readReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
   endmethod

   method ActionValue#(Bit#(32)) readData() if (!readingDirectory);
      let memData <- top.slave.read_server.readData.get();
      $display("read data=%h", memData.data);
      return memData.data;
   endmethod

   method Action write(Bit#(32) addr, Bit#(32) data);
      top.slave.write_server.writeReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0});
      top.slave.write_server.writeData.put(MemData { data: data, tag: 0, last: True });
   endmethod

`ifdef BSIMRESPONDER
   `BSIMRESPONDER (top.pins);
`endif
   interface Clock singleClock = single_clock;
   interface Reset singleReset = single_reset;
endmodule

// Copyright (c) 2015 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 FIFOF             :: *;
import FIFO              :: *;
import SpecialFIFOs      :: *;
import GetPut            :: *;
import Connectable       :: *;
import StmtFSM           :: *;
import Portal            :: *;
import Leds              :: *;
import Top               :: *;
import MemTypes          :: *;
import HostInterface     :: *;
import CtrlMux           :: *;
import ClientServer      :: *;
import PCIE              :: *;

`ifndef PinType
`define PinType Empty
`endif

typedef `PinType PinType;
typedef `NumberOfMasters NumberOfMasters;

module  mkXsimHost#(Clock derivedClock, Reset derivedReset)(XsimHost);
   interface derivedClock = derivedClock;
   interface derivedReset = derivedReset;
endmodule

interface XsimTop;
   method Action read(Bit#(32) addr);
   method ActionValue#(Bit#(32)) readData();
   method Action write(Bit#(32) addr, Bit#(32) data);

   interface Clock singleClock;
   interface Reset singleReset;
endinterface

module  mkXsimTop(XsimTop);
   //let divider <- mkClockDivider(2);
   Clock derivedClock <- exposeCurrentClock; //= divider.fastClock;
   Clock single_clock = derivedClock; //divider.slowClock;
   Reset derivedReset <- exposeCurrentReset;
   //let sr <- mkReset(2, True, single_clock);
   Reset single_reset = derivedReset; //sr.new_rst;

   XsimHost host <- mkXsimHost(clocked_by single_clock, reset_by single_reset, derivedClock, derivedReset);
   ConnectalTop#(PhysAddrWidth,DataBusWidth,PinType,NumberOfMasters) top <- mkConnectalTop(
`ifdef IMPORT_HOSTIF
       host,
`endif
       clocked_by single_clock, reset_by single_reset);
   //mapM(uncurry(mkConnection),zip(top.masters, host.mem_servers), clocked_by single_clock, reset_by single_reset);

   let intr_mux <- mkInterruptMux(top.interrupt);
   rule int_rule;
      //interruptLevel(truncate(pack(intr_mux)));
   endrule

   method Action read(Bit#(32) addr);
      $display("read addr=%h", addr);
      top.slave.read_server.readReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0 });
   endmethod

   method ActionValue#(Bit#(32)) readData();
      let memData <- top.slave.read_server.readData.get();
      $display("read data=%h", memData.data);
      return memData.data;
   endmethod

   method Action write(Bit#(32) addr, Bit#(32) data);
      top.slave.write_server.writeReq.put(PhysMemRequest { addr: addr, burstLen: 4, tag: 0});
      top.slave.write_server.writeData.put(MemData { data: data, tag: 0, last: True });
   endmethod

`ifdef BSIMRESPONDER
   `BSIMRESPONDER (top.pins);
`endif
   interface Clock singleClock = single_clock;
   interface Reset singleReset = single_reset;
endmodule


Fixed a guard.

Fixed a guard.

Change-Id: Ibd1a51d3a7ac6aab0f29d6ee1c3fd8f185e1d4c2

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

// BSV Libraries
import FIFOF::*;
import Vector::*;
import GetPutF::*;
import ClientServer::*;
import BRAMFIFO::*;
import BRAM::*;

// XBSV Libraries
import PortalMemory::*;
import PortalRMemory::*;
import Adapter::*;

import "BDPI" function Action pareff(Bit#(32) handle, Bit#(32) size);
import "BDPI" function Action init_pareff();
import "BDPI" function Action write_pareff32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_pareff64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_pareff32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_pareff64(Bit#(32) handle, Bit#(32) addr);

interface BsimRdmaReadWrite#(numeric type dsz);
   method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(dsz) v);
   method ActionValue#(Bit#(dsz)) read_pareff(Bit#(32) handle, Bit#(32) addr);
endinterface

typeclass SelectBsimRdmaReadWrite#(numeric type dsz);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(dsz) ifc);
endtypeclass

instance SelectBsimRdmaReadWrite#(32);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(32) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
	  write_pareff32(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(32)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff32(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(64);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(64) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
	  write_pareff64(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(64)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff64(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(128);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(128) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(128) v);
	  write_pareff64(handle, addr, v[63:0]);
	  write_pareff64(handle, addr+8, v[127:64]);
       endmethod
       method ActionValue#(Bit#(128)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v0 <- read_pareff64(handle, addr);
	  let v1 <- read_pareff64(handle, addr+8);
	  return {v1,v0};
       endmethod
   endmodule
endinstance

//
// @brief DMA server for use in Bluesim
//
// @param dsz Number of bits in the data bus
//
interface BsimDMAServer#(numeric type dsz);
   interface DMARequest request;
endinterface

module mkBsimDMAReadInternal#(Vector#(numReadClients, DMAReadClient#(dsz)) readClients)(DMARead)
      provisos (SelectBsimRdmaReadWrite#(dsz));

   let dsz = valueOf(dsz);
   let rw <- selectBsimRdmaReadWrite();

   Reg#(DmaMemHandle)     handleReg <- mkReg(0);
   Reg#(Bit#(DmaAddrSize))  addrReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bit#(8))           tagReg <- mkReg(0);
   Reg#(DmaChannelId)  activeChan <- mkReg(0);
   Reg#(DmaChannelId)   selectReg <- mkReg(0);

   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numReadClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule loadClient if (burstReg == 0 && readClients[selectReg].readData.notFull());
      activeChan <= selectReg;
      let req <- readClients[selectReg].readReq.get();
      //$display("dmaread.loadClient activeChan=%d handle=%h addr=%h burst=%h", selectReg, req.handle, req.address, req.burstLen);
      handleReg <= req.handle;
      addrReg <= req.address;
      burstReg <= req.burstLen;
      tagReg <= req.tag;
   endrule

   rule readData if (burstReg > 0);
      addrReg <= addrReg+fromInteger(valueOf(TDiv#(dsz,8)));
      burstReg <= burstReg-1;
      Bit#(32) addr = extend(addrReg);
      Bit#(dsz) v <- rw.read_pareff(handleReg, addr);
      //$display("dmaread.readData activeChan=%d handle=%h addr=%h burst=%h v=%h", activeChan, handleReg, addrReg, burstReg, v);
      readClients[activeChan].readData.put(DMAData { data: v, tag: tagReg});
   endrule

   method ActionValue#(DmaDbgRec) dbg();
      return ?;
   endmethod

endmodule

module mkBsimDMAWriteInternal#(Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients)(DMAWrite)
      provisos (SelectBsimRdmaReadWrite#(dsz));

   let dsz = valueOf(dsz);
   let rw <- selectBsimRdmaReadWrite();

   Reg#(DmaMemHandle)   handleReg <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) addrReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bit#(8))           tagReg <- mkReg(0);
   Reg#(DmaChannelId)  activeChan <- mkReg(0);
   Reg#(DmaChannelId)   selectReg <- mkReg(0);

   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numWriteClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule loadClient if (burstReg == 0 && writeClients[selectReg].writeData.notEmpty());
      activeChan <= selectReg;
      let req   <- writeClients[selectReg].writeReq.get();
      //$display("dmawrite.loadClient activeChan=%d handle=%h addr=%h burst=%h", selectReg, req.handle, req.address, req.burstLen);
      handleReg   <= req.handle;
      addrReg   <= req.address;
      burstReg  <= req.burstLen;
      tagReg    <= req.tag;
   endrule

   rule writeData if (burstReg > 0);
      addrReg <= addrReg+fromInteger(valueOf(TDiv#(dsz,8)));
      let v <- writeClients[activeChan].writeData.get();
      if (v.tag != tagReg) begin
	 //$display("BsimWriteData tag mismatch %h expected %h", v.tag, tagReg);
      end
      if (burstReg == 1)
	 writeClients[activeChan].writeDone.put(v.tag);
      burstReg <= burstReg-1;
      //$display("writeData activeChan=%d handle=%h addr=%h", activeChan, handleReg, addrReg);
      Bit#(32) addr = extend(addrReg);
      rw.write_pareff(handleReg, addr, v.data);
   endrule

   method ActionValue#(DmaDbgRec) dbg();
      return ?;
   endmethod

endmodule

//
// @brief Creates a DMA controller for read and write clients
//
// @param dmaIndication Interface for notifying software
// @param readClients The read clients.
// @param writeClients The writeclients.
//
module mkBsimDMAServer#(DMAIndication dmaIndication,
			Vector#(numReadClients, DMAReadClient#(dsz)) readClients,
			Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients)
   (BsimDMAServer#(dsz))
   provisos (SelectBsimRdmaReadWrite#(dsz));

   Reg#(Bool) inited <- mkReg(False);

   DMARead reader;
   if (valueOf(numReadClients) > 0)
      reader <- mkBsimDMAReadInternal(readClients);
   else
      reader = (interface DMARead;
		   method ActionValue#(DmaDbgRec) dbg();
		      return ?;
		   endmethod
		endinterface);

   DMAWrite writer;
   if (valueOf(numWriteClients) > 0)
      writer <- mkBsimDMAWriteInternal(writeClients);
   else
      writer = (interface DMAWrite;
		    method ActionValue#(DmaDbgRec) dbg();
		        return ?;
		    endmethod
		endinterface);

   rule initialize(!inited);
      inited <= True;
      init_pareff();
   endrule

   interface DMARequest request;
      method Action getStateDbg(ChannelType rc);
	 let rv = ?;
	 if (rc == Read)
	    rv <- reader.dbg;
	 if (rc == Write)
	    rv <- writer.dbg;
	 dmaIndication.reportStateDbg(rv);
      endmethod
      method Action paref(Bit#(32) handle, Bit#(32) size);
	 pareff(handle, size);
	 dmaIndication.parefResp(handle);
      endmethod
   endinterface
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.

// BSV Libraries
import FIFOF::*;
import Vector::*;
import GetPutF::*;
import ClientServer::*;
import BRAMFIFO::*;
import BRAM::*;

// XBSV Libraries
import PortalMemory::*;
import PortalRMemory::*;
import Adapter::*;

import "BDPI" function Action pareff(Bit#(32) handle, Bit#(32) size);
import "BDPI" function Action init_pareff();
import "BDPI" function Action write_pareff32(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
import "BDPI" function Action write_pareff64(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
import "BDPI" function ActionValue#(Bit#(32)) read_pareff32(Bit#(32) handle, Bit#(32) addr);
import "BDPI" function ActionValue#(Bit#(64)) read_pareff64(Bit#(32) handle, Bit#(32) addr);

interface BsimRdmaReadWrite#(numeric type dsz);
   method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(dsz) v);
   method ActionValue#(Bit#(dsz)) read_pareff(Bit#(32) handle, Bit#(32) addr);
endinterface

typeclass SelectBsimRdmaReadWrite#(numeric type dsz);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(dsz) ifc);
endtypeclass

instance SelectBsimRdmaReadWrite#(32);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(32) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(32) v);
	  write_pareff32(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(32)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff32(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(64);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(64) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(64) v);
	  write_pareff64(handle, addr, v);
       endmethod
       method ActionValue#(Bit#(64)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v <- read_pareff64(handle, addr);
	  return v;
       endmethod
   endmodule
endinstance
instance SelectBsimRdmaReadWrite#(128);
   module selectBsimRdmaReadWrite(BsimRdmaReadWrite#(128) ifc);
       method Action write_pareff(Bit#(32) handle, Bit#(32) addr, Bit#(128) v);
	  write_pareff64(handle, addr, v[63:0]);
	  write_pareff64(handle, addr+8, v[127:64]);
       endmethod
       method ActionValue#(Bit#(128)) read_pareff(Bit#(32) handle, Bit#(32) addr);
	  let v0 <- read_pareff64(handle, addr);
	  let v1 <- read_pareff64(handle, addr+8);
	  return {v1,v0};
       endmethod
   endmodule
endinstance

//
// @brief DMA server for use in Bluesim
//
// @param dsz Number of bits in the data bus
//
interface BsimDMAServer#(numeric type dsz);
   interface DMARequest request;
endinterface

module mkBsimDMAReadInternal#(Vector#(numReadClients, DMAReadClient#(dsz)) readClients)(DMARead)
      provisos (SelectBsimRdmaReadWrite#(dsz));

   let dsz = valueOf(dsz);
   let rw <- selectBsimRdmaReadWrite();

   Reg#(DmaMemHandle)     handleReg <- mkReg(0);
   Reg#(Bit#(DmaAddrSize))  addrReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bit#(8))           tagReg <- mkReg(0);
   Reg#(DmaChannelId)  activeChan <- mkReg(0);
   Reg#(DmaChannelId)   selectReg <- mkReg(0);

   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numReadClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule loadClient if (burstReg == 0 && readClients[selectReg].readData.notFull());
      activeChan <= selectReg;
      let req <- readClients[selectReg].readReq.get();
      //$display("dmaread.loadClient activeChan=%d handle=%h addr=%h burst=%h", selectReg, req.handle, req.address, req.burstLen);
      handleReg <= req.handle;
      addrReg <= req.address;
      burstReg <= req.burstLen;
      tagReg <= req.tag;
   endrule

   rule readData if (burstReg > 0);
      addrReg <= addrReg+fromInteger(valueOf(TDiv#(dsz,8)));
      burstReg <= burstReg-1;
      Bit#(32) addr = extend(addrReg);
      Bit#(dsz) v <- rw.read_pareff(handleReg, addr);
      //$display("dmaread.readData activeChan=%d handle=%h addr=%h burst=%h v=%h", activeChan, handleReg, addrReg, burstReg, v);
      readClients[activeChan].readData.put(DMAData { data: v, tag: tagReg});
   endrule

   method ActionValue#(DmaDbgRec) dbg();
      return ?;
   endmethod

endmodule

module mkBsimDMAWriteInternal#(Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients)(DMAWrite)
      provisos (SelectBsimRdmaReadWrite#(dsz));

   let dsz = valueOf(dsz);
   let rw <- selectBsimRdmaReadWrite();

   Reg#(DmaMemHandle)   handleReg <- mkReg(0);
   Reg#(Bit#(DmaAddrSize)) addrReg <- mkReg(0);
   Reg#(Bit#(8))         burstReg <- mkReg(0);
   Reg#(Bit#(8))           tagReg <- mkReg(0);
   Reg#(DmaChannelId)  activeChan <- mkReg(0);
   Reg#(DmaChannelId)   selectReg <- mkReg(0);

   rule incSelectReg;
      let s = selectReg+1;
      if (s == fromInteger(valueOf(numWriteClients)))
	 s = 0;
      selectReg <= s;
   endrule

   rule loadClient if (burstReg == 0 && writeClients[activeChan].writeData.notEmpty());
      activeChan <= selectReg;
      let req   <- writeClients[selectReg].writeReq.get();
      //$display("dmawrite.loadClient activeChan=%d handle=%h addr=%h burst=%h", selectReg, req.handle, req.address, req.burstLen);
      handleReg   <= req.handle;
      addrReg   <= req.address;
      burstReg  <= req.burstLen;
      tagReg    <= req.tag;
   endrule

   rule writeData if (burstReg > 0);
      addrReg <= addrReg+fromInteger(valueOf(TDiv#(dsz,8)));
      let v <- writeClients[activeChan].writeData.get();
      if (v.tag != tagReg) begin
	 //$display("BsimWriteData tag mismatch %h expected %h", v.tag, tagReg);
      end
      if (burstReg == 1)
	 writeClients[activeChan].writeDone.put(v.tag);
      burstReg <= burstReg-1;
      //$display("writeData activeChan=%d handle=%h addr=%h", activeChan, handleReg, addrReg);
      Bit#(32) addr = extend(addrReg);
      rw.write_pareff(handleReg, addr, v.data);
   endrule

   method ActionValue#(DmaDbgRec) dbg();
      return ?;
   endmethod

endmodule

//
// @brief Creates a DMA controller for read and write clients
//
// @param dmaIndication Interface for notifying software
// @param readClients The read clients.
// @param writeClients The writeclients.
//
module mkBsimDMAServer#(DMAIndication dmaIndication,
			Vector#(numReadClients, DMAReadClient#(dsz)) readClients,
			Vector#(numWriteClients, DMAWriteClient#(dsz)) writeClients)
   (BsimDMAServer#(dsz))
   provisos (SelectBsimRdmaReadWrite#(dsz));

   Reg#(Bool) inited <- mkReg(False);

   DMARead reader;
   if (valueOf(numReadClients) > 0)
      reader <- mkBsimDMAReadInternal(readClients);
   else
      reader = (interface DMARead;
		   method ActionValue#(DmaDbgRec) dbg();
		      return ?;
		   endmethod
		endinterface);

   DMAWrite writer;
   if (valueOf(numWriteClients) > 0)
      writer <- mkBsimDMAWriteInternal(writeClients);
   else
      writer = (interface DMAWrite;
		    method ActionValue#(DmaDbgRec) dbg();
		        return ?;
		    endmethod
		endinterface);

   rule initialize(!inited);
      inited <= True;
      init_pareff();
   endrule

   interface DMARequest request;
      method Action getStateDbg(ChannelType rc);
	 let rv = ?;
	 if (rc == Read)
	    rv <- reader.dbg;
	 if (rc == Write)
	    rv <- writer.dbg;
	 dmaIndication.reportStateDbg(rv);
      endmethod
      method Action paref(Bit#(32) handle, Bit#(32) size);
	 pareff(handle, size);
	 dmaIndication.parefResp(handle);
      endmethod
   endinterface
endmodule