https://blackmesalabs.wordpress.com/2016/10/24/sump2-96-msps-logic-analyzer-for-22/
[BML_sump2] / sump2 / source / sump2.v
diff --git a/sump2/source/sump2.v b/sump2/source/sump2.v
new file mode 100755 (executable)
index 0000000..a67db91
--- /dev/null
@@ -0,0 +1,814 @@
+/* ****************************************************************************\r
+-- (C) Copyright 2016 Kevin M. Hubbard - All rights reserved.\r
+-- Source file: sump2.v\r
+-- Date:        July 2016\r
+-- Author:      khubbard\r
+-- Description: SUMP2 is a fast and simple logic analyzer.\r
+--              It captures N/2 samples before and after a specified trigger\r
+--              event where N is length of BRAM specified when instantiated. \r
+--              It is designed to scale easily from small and simple to wide \r
+--              and deep block RAM primiting. \r
+-- Language:    Verilog-2001\r
+-- Simulation:  Mentor-Modelsim\r
+-- Synthesis:   Xilinst-XST, Lattice-Synplify\r
+-- License:     This project is licensed with the CERN Open Hardware Licence \r
+--              v1.2.  You may redistribute and modify this project under the \r
+--              terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl). \r
+--              This project is distributed WITHOUT ANY EXPRESS OR IMPLIED \r
+--              WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY \r
+--              AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL\r
+--              v.1.2 for applicable Conditions.\r
+--\r
+-- Design Instance Parameters with examples:\r
+--   depth_len      =  1024 : Depth of RAM in number of cell, example 1024,4096\r
+--   depth_bits     =  10   : Number of RAM address lines,    example 10,12\r
+--   event_bytes    =  4    : Number of event bytes 1,2,3 or 4\r
+--   data_dwords    =  16   : Number of DWORDs for Data 0,4,8,12 or 16\r
+--\r
+--   nonrle_en      =  1 : If 0, removes Event RAM (for small RLE only designs)\r
+--   rle_en         =  1 : Adds logic for Event RLE captures.\r
+--   pattern_en     =  1 : Adds logic for 32bit event pattern triggers\r
+--   trigger_nth_en =  1 : Adds logic for triggering on Nth trigger event\r
+--   trigger_dly_en =  1 : Adds logic for triggering after a delay from trigger\r
+--\r
+--   freq_mhz       =  16'd80   : Freq integer 0 MHz up to 65 GHz ( 16bit )\r
+--   freq_fracts    =  16'h0000 : Freq fraction bits, example C000 = 0.75 MHz\r
+--   sump_id        =  16'hABBA : Don't Change\r
+--   sump_rev       =   8'h01   : Don't Change\r
+--\r
+-- LocalBus 2 DWORD Register Interface\r
+--   lb_cs_ctrl : PCI addr sel for Control \r
+--   lb_cs_data : PCI addr sel for Data transfers. +0x4 offset from lb_cs_ctrl\r
+--\r
+-- Software Interface\r
+-- 5bit Control Commands:\r
+--   0x00 : Idle + Read Status\r
+--   0x01 : ARM  + Read Status\r
+--   0x02 : Reset\r
+--              \r
+--   0x04 : Load Trigger Type  ( AND,OR,Ext )\r
+--   0x05 : Load Trigger Field ( AND/OR bits )\r
+--   0x06 : Load Trigger Delay & nth        \r
+--   0x07 : Load Trigger Position ( Num Post Trigger Samples to capture ).\r
+--\r
+--   0x08 : Load RLE Event Enable\r
+--   0x09 : Load Read Pointer\r
+--   0x0a : Load Read Page\r
+--              \r
+--   0x0b : Read HW ID + Revision\r
+--   0x0c : Read HW Config RAM Width+Length\r
+--   0x0d : Read HW Config Sample Clock Frequency\r
+--   0x0e : Read Trigger Location\r
+--   0x0f : Read RAM Data ( address auto incrementing )\r
+--\r
+--   0x10 : Load User Controls\r
+--   0x11 : Load User Pattern0\r
+--   0x12 : Load User Pattern1\r
+--   0x13 : Load Data Enable Field\r
+--\r
+-- Trigger Types:\r
+--   AND Rising            = 0x00;\r
+--   AND Falling           = 0x01;\r
+--   OR  Rising            = 0x02;\r
+--   OR  Falling           = 0x03;\r
+--   Pattern Rising        = 0x04;\r
+--   Pattern Falling       = 0x05;\r
+--   Input Trigger Rising  = 0x06;\r
+--   Input Trigger Falling = 0x07;\r
+--\r
+-- Revision History:\r
+-- Ver#  When      Who      What\r
+-- ----  --------  -------- --------------------------------------------------\r
+-- 0.1   07.01.16  khubbard Creation\r
+-- ***************************************************************************/\r
+`default_nettype none // Strictly enforce all nets to be declared\r
+\r
+\r
+module sump2 #\r
+(\r
+   parameter depth_len      =  1024,\r
+   parameter depth_bits     =  10,\r
+   parameter event_bytes    =  4,\r
+   parameter data_dwords    =  16,\r
+\r
+   parameter nonrle_en      =  1,\r
+   parameter rle_en         =  1,\r
+   parameter pattern_en     =  1,\r
+   parameter trigger_nth_en =  1,\r
+   parameter trigger_dly_en =  1,\r
+   parameter trigger_wd_en  =  1,\r
+\r
+   parameter freq_mhz       =  16'd80,\r
+   parameter freq_fracts    =  16'h0000,\r
+   parameter sump_id        =  16'hABBA,\r
+   parameter sump_rev       =   8'h01\r
+)\r
+(\r
+  input  wire         reset,\r
+  input  wire         clk_cap,\r
+  input  wire         clk_lb,\r
+  input  wire         lb_cs_ctrl,\r
+  input  wire         lb_cs_data,\r
+  input  wire         lb_wr,\r
+  input  wire         lb_rd,\r
+  input  wire [31:0]  lb_wr_d,\r
+  output reg  [31:0]  lb_rd_d,\r
+  output reg          lb_rd_rdy,\r
+  output reg          active,\r
+\r
+  output wire [31:0]  user_ctrl,\r
+  output wire [31:0]  user_pat0,\r
+  output wire [31:0]  user_pat1,\r
+\r
+  input  wire         trigger_in,\r
+  output reg          trigger_out,\r
+\r
+  input  wire [31:0]  events_din,\r
+\r
+  input  wire [127:0] dwords_3_0,\r
+  input  wire [127:0] dwords_7_4,\r
+  input  wire [127:0] dwords_11_8,\r
+  input  wire [127:0] dwords_15_12,\r
+  output reg  [3:0]   led_bus\r
+);\r
+\r
+\r
+  wire                    reset_loc;\r
+  wire [15:0]             zeros;\r
+  wire [15:0]             ones;\r
+  wire [7:0]              cap_status;\r
+  wire [4:0]              ctrl_cmd;\r
+  reg  [4:0]              ctrl_cmd_loc;\r
+  reg                     ctrl_cmd_xfer;\r
+  wire [4:0]              ctrl_rd_page;\r
+  wire [15:0]             ctrl_rd_ptr;\r
+  wire                    ctrl_trigger_edge;\r
+  wire [4:0]              ctrl_trigger;\r
+  reg  [4:0]              ctrl_trigger_p1;\r
+  reg  [4:0]              ctrl_reg;\r
+  reg  [31:0]             events_loc;\r
+  reg                     trigger_loc;\r
+  reg                     trigger_or;\r
+  reg                     trigger_or_p1;\r
+  reg                     trigger_and;\r
+  reg                     trigger_and_p1;\r
+  reg                     trigger_pat;\r
+  reg                     trigger_pat_p1;\r
+  reg                     xfer_clr;\r
+  reg                     rd_inc;\r
+  reg                     armed_jk;\r
+  reg                     triggered_jk;\r
+  reg                     acquired_jk;\r
+  reg                     complete_jk;\r
+\r
+  reg  [31:0]             ctrl_04_reg;\r
+  reg  [31:0]             ctrl_05_reg;\r
+  reg  [31:0]             ctrl_06_reg;\r
+  reg  [31:0]             ctrl_07_reg;\r
+  reg  [31:0]             ctrl_08_reg;\r
+  reg  [31:0]             ctrl_09_reg;\r
+  reg  [31:0]             ctrl_0a_reg;\r
+  reg  [31:0]             ctrl_0b_reg;\r
+  reg  [31:0]             ctrl_10_reg;\r
+  reg  [31:0]             ctrl_11_reg;\r
+  reg  [31:0]             ctrl_12_reg;\r
+  reg  [31:0]             ctrl_13_reg;\r
+\r
+  reg  [31:0]             ctrl_14_reg;\r
+  wire [31:0]             watchdog_reg;\r
+  reg  [31:0]             watchdog_cnt;\r
+  reg                     wd_armed_jk;\r
+  reg                     trigger_wd;\r
+\r
+  wire [31:0]             trigger_bits;\r
+  wire [3:0]              trigger_type;\r
+  wire [31:0]             trigger_pos;\r
+  wire [15:0]             trigger_nth;\r
+  wire [15:0]             trigger_delay;\r
+  reg  [15:0]             trigger_dly_cnt;\r
+  wire [31:0]             rle_event_en;\r
+  reg  [15:0]             trigger_cnt;\r
+  reg  [31:0]             ram_rd_d;\r
+  reg  [depth_bits-1:0]   post_trig_cnt;\r
+  reg  [depth_bits-1:0]   trigger_ptr;\r
+  reg                     trigger_in_meta;\r
+  reg                     trigger_in_p1;\r
+  reg                     trigger_in_p2;\r
+  wire [31:0]             pat0;\r
+  wire [31:0]             pat1;\r
+\r
+// Variable Size Capture BRAM\r
+  reg  [31:0]             event_ram_array[depth_len-1:0];\r
+  reg  [127:0]            dwords_3_0_ram_array[depth_len-1:0];\r
+  reg  [127:0]            dwords_7_4_ram_array[depth_len-1:0];\r
+  reg  [127:0]            dwords_11_8_ram_array[depth_len-1:0];\r
+  reg  [127:0]            dwords_15_12_ram_array[depth_len-1:0];\r
+\r
+  reg  [127:0]            dwords_3_0_p1;\r
+  reg  [127:0]            dwords_7_4_p1;\r
+  reg  [127:0]            dwords_11_8_p1;\r
+  reg  [127:0]            dwords_15_12_p1;\r
+\r
+  reg  [127:0]            dwords_3_0_p2;\r
+  reg  [127:0]            dwords_7_4_p2;\r
+  reg  [127:0]            dwords_11_8_p2;\r
+  reg  [127:0]            dwords_15_12_p2;\r
+\r
+  reg  [127:0]            dwords_3_0_do;\r
+  reg  [127:0]            dwords_7_4_do;\r
+  reg  [127:0]            dwords_11_8_do;\r
+  reg  [127:0]            dwords_15_12_do;\r
+\r
+  reg  [depth_bits-1:0]   c_addr;\r
+  reg  [depth_bits-1:0]   c_addr_p1;\r
+  reg                     c_we;\r
+  reg                     c_we_p1;\r
+  wire [31:0]             c_di;\r
+  reg  [31:0]             c_di_p1;\r
+  reg  [depth_bits-1:0]   d_addr;\r
+  reg  [31:0]             d_do;\r
+\r
+  reg  [63:0]             rle_ram_array[depth_len-1:0];\r
+  reg  [depth_bits-1:0]   a_addr;\r
+  reg  [depth_bits-1:0]   a_addr_p1;\r
+  reg                     a_we;\r
+  reg                     a_we_p1;\r
+  reg  [63:0]             a_di;\r
+  reg  [63:0]             a_di_p1;\r
+  reg  [depth_bits-1:0]   b_addr;\r
+  reg  [63:0]             b_do;\r
+\r
+  wire [31:0]             data_en_bits;\r
+  reg                     data_en_loc;\r
+  reg                     data_en_loc_p1;\r
+  reg  [31:0]             events_pre;\r
+  reg  [31:0]             events_p1;\r
+  reg  [31:0]             events_p2;\r
+  reg  [31:0]             rle_time;\r
+  reg  [31:0]             rle_time_p1;\r
+  reg                     rle_wd_sample;\r
+  reg                     rle_pre_jk;\r
+  reg                     rle_done_jk;\r
+  wire [7:0]              data_4x_dwords;\r
+\r
+\r
+  assign zeros = 16'd0;\r
+  assign ones  = 16'hFFFF;\r
+  assign reset_loc = reset;\r
+\r
\r
+  assign cap_status = { rle_en, 1'b0, rle_done_jk, ~rle_pre_jk,\r
+                        complete_jk, acquired_jk, triggered_jk, armed_jk }; \r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Flop the input events and support reduction for much smaller designs.\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk_cap ) begin : proc_din \r
+  if          ( event_bytes == 1 ) begin\r
+    events_loc <= { 24'd0, events_din[7:0] };\r
+  end else if ( event_bytes == 2 ) begin\r
+    events_loc <= { 16'd0, events_din[15:0] };\r
+  end else if ( event_bytes == 3 ) begin\r
+    events_loc <= {  8'd0, events_din[23:0] };\r
+  end else begin\r
+    events_loc <= {        events_din[31:0] };\r
+  end\r
+\r
+  if ( rle_en == 1 ) begin\r
+    events_pre <= events_loc[31:0] & rle_event_en[31:0];\r
+    events_p1  <= events_pre[31:0];\r
+    events_p2  <= events_p1[31:0];\r
+  end \r
+end // proc_din\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Capture Logic. When armed, capture in a continuous loop until trigger is\r
+// detected and then capture N/2 samples more.\r
+// Note: Software Must go from Idle to Arm to clear the JKs.\r
+//-----------------------------------------------------------------------------\r
+always @ ( * ) begin : proc_data_en\r
+  if ( data_en_bits == 32'h00000000 ||\r
+       ( data_en_bits[31:0] & events_din[31:0] ) != 32'h00000000 ) begin\r
+    data_en_loc <= 1;// Capture sample in time \r
+  end else begin\r
+    data_en_loc <= 0;// Prevent sample capture\r
+  end\r
+end // proc_data_en\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Capture Logic. When armed, capture in a continuous loop until trigger is\r
+// detected and then capture N/2 samples more.\r
+// Note: Software Must go from Idle to Arm to clear the JKs.\r
+//-----------------------------------------------------------------------------\r
+integer i;\r
+always @ ( posedge clk_cap ) begin : proc_trig \r
+  trigger_in_meta <= trigger_in;\r
+  trigger_in_p1   <= trigger_in_meta;\r
+  trigger_in_p2   <= trigger_in_p1;\r
+  trigger_or      <= 0;\r
+  trigger_and     <= 0;\r
+  trigger_pat     <= 0;\r
+  trigger_or_p1   <= trigger_or;\r
+  trigger_and_p1  <= trigger_and;\r
+  trigger_pat_p1  <= trigger_pat;\r
+  data_en_loc_p1  <= data_en_loc;\r
+\r
+  for ( i = 0; i <= 31; i=i+1 ) begin\r
+    if ( trigger_bits[i] == 1 && events_loc[i] == 1 ) begin\r
+      trigger_or <= 1;// This is a 32bit OR\r
+    end\r
+  end\r
+  \r
+  if ( ( events_loc[31:0] & trigger_bits[31:0] ) == trigger_bits[31:0] ) begin\r
+    trigger_and <= 1;\r
+  end \r
+\r
+  if ( \r
+      (( events_loc[31:0] & pat0[31:0] ) ^  \r
+       ( pat1[31:0]       & pat0[31:0] )   ) == 32'h00000000  ) begin\r
+\r
+    if ( pattern_en == 1 ) begin\r
+      trigger_pat <= 1;// Exact 32bit Pattern Match\r
+    end \r
+  end \r
\r
+end // proc_trig\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Capture Logic. When armed, capture in a continuous loop until trigger is\r
+// detected and then capture N/2 samples more.\r
+// Note: Software Must go from Idle to Arm to clear the JKs.\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk_cap ) begin : proc_cap  \r
+  c_we        <= 0;\r
+  trigger_out <= 0;\r
+  trigger_loc <= 0;\r
+  trigger_wd  <= 0;\r
+  active      <= 0;\r
+\r
+  // CMD_ARM   \r
+  if ( ctrl_cmd_loc == 5'h01 ) begin\r
+    active <= 1;\r
+\r
+    // Watchdog gets armed on 1st kick. Every kick after clears count.\r
+    // If count expires, assert trigger_wd.\r
+    if ( trigger_wd_en == 1 && ( trigger_or != trigger_or_p1 ) ) begin\r
+      wd_armed_jk <= 1;\r
+    end\r
+    if ( wd_armed_jk == 0 || ( trigger_or != trigger_or_p1 ) ) begin\r
+      watchdog_cnt <= 32'd0;\r
+      trigger_wd   <= 0;\r
+    end else begin\r
+      watchdog_cnt <= watchdog_cnt[31:0] + 1;\r
+      if ( watchdog_cnt == watchdog_reg[31:0] ) begin\r
+        trigger_wd  <= 1;\r
+        wd_armed_jk <= 0;\r
+      end  \r
+    end \r
+\r
+    if ( triggered_jk == 0 && acquired_jk == 0 ) begin\r
+      // PreTrigger Acquire\r
+      armed_jk <= 1;\r
+      if ( data_en_loc == 1 || data_en_loc_p1 == 1 ) begin\r
+        c_we     <= 1;\r
+        c_addr   <= c_addr + 1;\r
+      end\r
+\r
+      if ( trigger_dly_cnt != 16'hFFFF ) begin\r
+        trigger_dly_cnt <= trigger_dly_cnt + 1;\r
+      end\r
+\r
+      if ( ( trigger_type==4'h0 && trigger_and==1    && trigger_and_p1==0 ) ||\r
+           ( trigger_type==4'h1 && trigger_and==0    && trigger_and_p1==1 ) ||\r
+           ( trigger_type==4'h2 && trigger_or ==1    && trigger_or_p1 ==0 ) ||\r
+           ( trigger_type==4'h3 && trigger_or ==0    && trigger_or_p1 ==1 ) ||\r
+           ( trigger_type==4'h4 && trigger_pat==1    && trigger_pat_p1==0 ) ||\r
+           ( trigger_type==4'h5 && trigger_pat==0    && trigger_pat_p1==1 ) ||\r
+           ( trigger_type==4'h6 && trigger_in_p1 ==1 && trigger_in_p2 ==0 ) ||\r
+           ( trigger_type==4'h7 && trigger_in_p1 ==0 && trigger_in_p2 ==1 ) ||\r
+           ( trigger_type==4'h8 && trigger_wd == 1                        )\r
+         ) begin\r
+        if ( trigger_dly_cnt == 16'hFFFF || trigger_dly_en==0 ) begin\r
+          trigger_dly_cnt <= 16'd0;\r
+          trigger_loc     <= 1;// Only used if trigger delay is removed\r
+          c_we            <= 1;// Store Trigger even if data_en_loc == 0\r
+          c_addr          <= c_addr + 1;\r
+        end\r
+      end\r
+\r
+      // Don't allow trigger until pre-trig buffer is full\r
+      if ( complete_jk == 1 ) begin\r
+        if ( ( trigger_dly_cnt == trigger_delay[15:0] ) || \r
+             (  trigger_dly_en==0 && trigger_loc == 1 ) ) begin\r
+          trigger_dly_cnt <= 16'hFFFF;\r
+          if ( trigger_cnt == trigger_nth[15:0] || trigger_nth_en==0 ) begin\r
+            armed_jk     <= 0;\r
+            trigger_ptr  <= c_addr[depth_bits-1:0];\r
+            trigger_out  <= 1;\r
+            triggered_jk <= 1;\r
+          end\r
+          trigger_cnt <= trigger_cnt + 1;\r
+        end\r
+      end\r
+\r
+    end else if ( triggered_jk == 1 && acquired_jk == 0 ) begin\r
+      // PostTrigger Acquire\r
+      trigger_out <= 1;\r
+      if ( data_en_loc == 1 || data_en_loc_p1 == 1 ) begin\r
+        c_we          <= 1;\r
+        c_addr        <= c_addr + 1;\r
+        post_trig_cnt <= post_trig_cnt + 1;\r
+      end\r
+      if ( post_trig_cnt == trigger_pos[depth_bits-1:0] ) begin\r
+        acquired_jk <= 1;\r
+        c_we        <= 0;\r
+      end \r
+    end\r
+\r
+    // If RAM has rolled, then pre-trigger buffer is full. Assert status bit.\r
+    // If RAM hasn't rolled, then pre-trigger samples start at 0x0.\r
+    if ( c_addr[depth_bits-1] == 0 && c_addr_p1[depth_bits-1] == 1 ) begin\r
+      complete_jk <= 1;\r
+    end\r
+\r
+  // CMD_RESET\r
+  end else if ( ctrl_cmd_loc == 5'h02 ) begin\r
+    c_addr             <= zeros[depth_bits-1:0];\r
+    post_trig_cnt      <= zeros[depth_bits-1:0];\r
+    post_trig_cnt[1:0] <= 2'b11;// Subtracts 3 from trigger_pos for alignment\r
+    trigger_cnt        <= 16'd1;\r
+    trigger_dly_cnt    <= 16'hFFFF;\r
+    armed_jk           <= 0;\r
+    triggered_jk       <= 0;\r
+    acquired_jk        <= 0;\r
+    complete_jk        <= 0;\r
+    wd_armed_jk        <= 0;\r
+  end\r
+\r
+  // Cleanly xfer clock domains\r
+  xfer_clr <= 0;\r
+  if ( ctrl_cmd_xfer == 1 ) begin\r
+    ctrl_cmd_loc <= ctrl_cmd[4:0];\r
+    xfer_clr     <= 1;\r
+  end\r
+\r
+end // proc_cap\r
+  assign c_di = events_loc[31:0];\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// led_bus : Spins while waiting for trigger event. 2 Solids when done.\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk_cap ) begin : proc_led_bus\r
+  if ( rle_done_jk == 0 ) begin\r
+    led_bus <= 4'h0;\r
+  end\r
+  if ( ctrl_cmd_loc == 5'h01 ) begin\r
+    if          ( rle_time[25:24] == 2'd0 ) begin\r
+      led_bus <= 4'h1;\r
+    end else if ( rle_time[25:24] == 2'd1 ) begin\r
+      led_bus <= 4'h2;\r
+    end else if ( rle_time[25:24] == 2'd2 ) begin\r
+      led_bus <= 4'h4;\r
+    end else begin\r
+      led_bus <= 4'h8;\r
+    end \r
+    // After Trigger, but before completion, only flash Left and Right\r
+    if ( triggered_jk == 1 ) begin\r
+      led_bus[2] <= 1'b0;\r
+      led_bus[0] <= 1'b0;\r
+    end\r
+  end\r
+  if ( rle_done_jk == 1 ) begin\r
+    led_bus <= 4'hA;\r
+  end\r
+end\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// RLE Capture Logic. This captures and stores event changes along with \r
+// time stamps to a x64 BRAM. 1st half of RAM is any pre-trigger activity.\r
+// 2nd half of RAM is post-trigger activity. Pre-trig is circular and must\r
+// be unrolled by software in correct order. Enabling RLE block is optional.\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk_cap ) begin : proc_rle  \r
+  a_we        <= 0;\r
+  rle_time_p1 <= rle_time[31:0];\r
+  // Prevent RLE from hanging in cases where no activity happens after the\r
+  // trigger event by storing a non-changing sample periodically every\r
+  // 2^24 clock cycles about 100ms at 100 MHz \r
+  // 2^20 clock cycles about 10ms at 100 MHz x 1024 RAM = 10Sec\r
+  // rle_wd_sample  <= rle_time[23] & ~ rle_time_p1[23];\r
+  rle_wd_sample  <= rle_time[19] & ~ rle_time_p1[19];// About 5sec\r
+\r
+  // CMD_ARM   \r
+  if ( ctrl_cmd_loc == 5'h01 ) begin\r
+    rle_time <= rle_time[31:0] + 1;\r
+    if ( triggered_jk == 0 ) begin\r
+      a_addr[depth_bits-1] <= 0;// Pre-Trigger Half\r
+      // If the prebuffer is invalid, store everything, change or no change\r
+      // as to immediately fill up RAM with valid samples\r
+      // Once prebuffer is valid, only store event deltas ( RLE )\r
+      if ( rle_pre_jk == 1 || rle_wd_sample == 1 || \r
+           ( events_p1 != events_p2[31:0] ) ) begin\r
+        a_we <= 1;\r
+        a_addr[depth_bits-2:0] <= a_addr[depth_bits-2:0] + 1; \r
+        if ( a_addr[depth_bits-2:0] == ones[depth_bits-2:0] ) begin\r
+          rle_pre_jk <= 0;// PreBuffer is completely valid - and rolling\r
+        end\r
+      end\r
+    end else if ( triggered_jk == 1 && rle_done_jk == 0 ) begin\r
+      if ( ( events_p1 != events_p2[31:0] ) || ( rle_wd_sample == 1) ) begin\r
+        a_we <= 1;\r
+        a_addr[depth_bits-2:0] <= a_addr[depth_bits-2:0] + 1; \r
+        // If previous write was to last address in RAM, then call it quits\r
+        if ( a_addr[depth_bits-2:0] == ones[depth_bits-2:0] ) begin\r
+          rle_done_jk            <= 1;// Post-Trig RAM is full\r
+          a_we                   <= 0;\r
+          a_addr[depth_bits-2:0] <= a_addr[depth_bits-2:0];\r
+        end\r
+        // If previous cycle was pre-trig, set address to start of post trig\r
+        if ( a_addr[depth_bits-1] == 0 ) begin\r
+          a_addr[depth_bits-1]   <= 1;// Post-Trigger Half\r
+          a_addr[depth_bits-2:0] <= zeros[depth_bits-2:0];\r
+        end\r
+      end\r
+    end\r
+\r
+  // CMD_RESET\r
+  end else if ( ctrl_cmd_loc == 5'h02 ) begin\r
+    rle_time    <= 32'd0;// 43 seconds at 100 MHz\r
+    a_addr      <= zeros[depth_bits-1:0];\r
+    rle_pre_jk  <= 1;\r
+    rle_done_jk <= 0;\r
+  end\r
+  a_di[31:0]  <= events_p1[31:0];\r
+  a_di[63:32] <= rle_time[31:0];\r
+end // proc_rle\r
+//assign a_di[31:0]  = events_p1[31:0];\r
+//assign a_di[63:32] = rle_time[31:0];\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// LocalBus Write Ctrl register\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk_lb ) begin : proc_lb_wr\r
+  if ( lb_wr == 1 && lb_cs_ctrl == 1 ) begin\r
+    ctrl_reg[4:0] <= lb_wr_d[4:0];\r
+    ctrl_cmd_xfer <= 1;\r
+  end \r
+\r
+  if ( lb_wr == 1 && lb_cs_data == 1 ) begin\r
+    case( ctrl_cmd[4:0] )\r
+      5'h04 : ctrl_04_reg <= lb_wr_d[31:0];\r
+      5'h05 : ctrl_05_reg <= lb_wr_d[31:0];\r
+      5'h06 : ctrl_06_reg <= lb_wr_d[31:0];\r
+      5'h07 : ctrl_07_reg <= lb_wr_d[31:0];\r
+\r
+      5'h08 : ctrl_08_reg <= lb_wr_d[31:0];\r
+      5'h09 : ctrl_09_reg <= lb_wr_d[31:0];\r
+      5'h0A : ctrl_0a_reg <= lb_wr_d[31:0];\r
+      5'h0B : ctrl_0b_reg <= lb_wr_d[31:0];\r
+\r
+      5'h10 : ctrl_10_reg <= lb_wr_d[31:0];\r
+      5'h11 : ctrl_11_reg <= lb_wr_d[31:0];\r
+      5'h12 : ctrl_12_reg <= lb_wr_d[31:0];\r
+      5'h13 : ctrl_13_reg <= lb_wr_d[31:0];\r
+      5'h14 : ctrl_14_reg <= lb_wr_d[31:0];\r
+    endcase\r
+  end\r
+\r
+  if ( xfer_clr == 1 ) begin\r
+    ctrl_cmd_xfer  <= 0;\r
+  end\r
+\r
+  if ( ctrl_cmd == 5'h01 ) begin\r
+    d_addr  <= c_addr[depth_bits-1:0];// When Acq stops, d_addr will be last \r
+  end\r
+  if ( lb_wr == 1 && lb_cs_data == 1 && ctrl_cmd == 5'h09 ) begin\r
+    d_addr <= lb_wr_d[depth_bits-1:0];// Load user specified address\r
+  end \r
+  if ( rd_inc == 1 ) begin\r
+    d_addr  <= d_addr[depth_bits-1:0] + 1;// Auto Increment on each read\r
+  end \r
+\r
+  if ( reset_loc == 1 ) begin\r
+    ctrl_reg[4:0] <= 5'd0;\r
+    ctrl_cmd_xfer <= 1;// Flag to xfer ctrl_reg into other clock domain\r
+  end \r
+end\r
+\r
+  assign ctrl_cmd[4:0]     = ctrl_reg[4:0];\r
+\r
+  assign trigger_type      = ctrl_04_reg[3:0];\r
+  assign trigger_bits      = ctrl_05_reg[31:0];\r
+  assign trigger_nth       = ctrl_06_reg[15:0];\r
+  assign trigger_delay     = ctrl_06_reg[31:16];\r
+  assign trigger_pos       = ctrl_07_reg[31:0];\r
+  assign rle_event_en      = ctrl_08_reg[31:0];\r
+\r
+  assign user_ctrl[31:0]   = ctrl_10_reg[31:0];\r
+  assign user_pat0[31:0]   = ctrl_11_reg[31:0];\r
+  assign user_pat1[31:0]   = ctrl_12_reg[31:0];\r
+  assign pat0[31:0]        = ctrl_11_reg[31:0];\r
+  assign pat1[31:0]        = ctrl_12_reg[31:0];\r
+  assign data_en_bits[31:0] = ctrl_13_reg[31:0];\r
+  assign watchdog_reg[31:0] = ctrl_14_reg[31:0];\r
+\r
+  assign ctrl_rd_ptr[15:0] = ctrl_09_reg[15:0];\r
+  assign ctrl_rd_page[4:0] = ctrl_0a_reg[4:0];\r
+\r
+  assign data_4x_dwords = data_dwords;\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// LocalBus readback of ctrl_reg and data_reg\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk_lb ) begin : proc_lb_rd\r
+  lb_rd_d   <= 32'd0;\r
+  lb_rd_rdy <= 0;\r
+  rd_inc    <= 0;\r
+\r
+  if ( lb_rd == 1 && lb_cs_ctrl == 1 ) begin\r
+    lb_rd_d[4:0] <= ctrl_reg[4:0];\r
+    lb_rd_rdy    <= 1;\r
+  end \r
+\r
+  if ( lb_rd == 1 && lb_cs_data == 1 ) begin\r
+    lb_rd_rdy <= 1;\r
+    if ( ctrl_cmd == 5'h00 ||\r
+         ctrl_cmd == 5'h01    \r
+       ) begin\r
+      lb_rd_d[7:0] <= cap_status[7:0];\r
+    end\r
+    if ( ctrl_cmd == 5'h0b ) begin\r
+      lb_rd_d[31:16] <= sump_id;// Identification\r
+      lb_rd_d[15:8]  <= sump_rev;// Revision\r
+      lb_rd_d[7:5]   <= 3'd0;\r
+      lb_rd_d[4]     <= ~ nonrle_en;// Invert to disable backwards SW comptbl\r
+      lb_rd_d[3]     <= rle_en;\r
+      lb_rd_d[2]     <= pattern_en;\r
+      lb_rd_d[1]     <= trigger_nth_en;\r
+      lb_rd_d[0]     <= trigger_dly_en;\r
+    end\r
+    if ( ctrl_cmd == 5'h0c ) begin\r
+      lb_rd_d[31:28] <= rle_en     ;// 1 if RLE RAM exists\r
+      lb_rd_d[27:24] <= event_bytes;// How Many Event Bytes 1-4\r
+      lb_rd_d[23:16] <= data_4x_dwords[5:2];// How Many 32bit BRAMs data 4x \r
+      lb_rd_d[15:0]  <= depth_len;  // How deep RAMs are\r
+    end\r
+    if ( ctrl_cmd == 5'h0d ) begin\r
+      lb_rd_d[15:0]  <= freq_fracts;// Fractional MHz bits 1/2,1/4,etc.\r
+      lb_rd_d[31:16] <= freq_mhz   ;// Integer MHz\r
+    end\r
+    if ( ctrl_cmd == 5'h0e ) begin\r
+      lb_rd_d[depth_bits-1:0] <= trigger_ptr[depth_bits-1:0];// Where Trig Is\r
+    end\r
+    if ( ctrl_cmd == 5'h0f ) begin\r
+      lb_rd_d <= ram_rd_d[31:0];\r
+      rd_inc  <= 1;// Auto Increment RAM Address\r
+    end\r
+  end \r
+\r
+  if ( data_dwords != 0 ) begin\r
+    // Mux between the BRAMs\r
+    case( ctrl_rd_page[4:0] )\r
+      5'H02   : ram_rd_d <= b_do[31:0];   // RLE Data\r
+      5'H03   : ram_rd_d <= b_do[63:32];  // RLE Time\r
+\r
+      5'H10   : ram_rd_d <= dwords_3_0_do[31:0];\r
+      5'H11   : ram_rd_d <= dwords_3_0_do[63:32];\r
+      5'H12   : ram_rd_d <= dwords_3_0_do[95:64];\r
+      5'H13   : ram_rd_d <= dwords_3_0_do[127:96];\r
+\r
+      5'H14   : ram_rd_d <= dwords_7_4_do[31:0];\r
+      5'H15   : ram_rd_d <= dwords_7_4_do[63:32];\r
+      5'H16   : ram_rd_d <= dwords_7_4_do[95:64];\r
+      5'H17   : ram_rd_d <= dwords_7_4_do[127:96];\r
+\r
+      5'H18   : ram_rd_d <= dwords_11_8_do[31:0];\r
+      5'H19   : ram_rd_d <= dwords_11_8_do[63:32];\r
+      5'H1a   : ram_rd_d <= dwords_11_8_do[95:64];\r
+      5'H1b   : ram_rd_d <= dwords_11_8_do[127:96];\r
+\r
+      5'H1c   : ram_rd_d <= dwords_15_12_do[31:0];\r
+      5'H1d   : ram_rd_d <= dwords_15_12_do[63:32];\r
+      5'H1e   : ram_rd_d <= dwords_15_12_do[95:64];\r
+      5'H1f   : ram_rd_d <= dwords_15_12_do[127:96];\r
+\r
+      default : ram_rd_d <= d_do[31:0];    // Events\r
+    endcase\r
+  end else begin\r
+    // Mux between the BRAMs\r
+    case( ctrl_rd_page[4:0] )\r
+      5'H02   : ram_rd_d <= b_do[31:0]; // RLE Data\r
+      5'H03   : ram_rd_d <= b_do[63:32];// RLE Time\r
+      default : ram_rd_d <= d_do[31:0]; // Events\r
+    endcase\r
+  end \r
+\r
+end // proc_lb_rd\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Data Dual Port RAM - Infer RAM here to make easy to change depth on the fly\r
+//-----------------------------------------------------------------------------\r
+always @( posedge clk_cap  )\r
+begin\r
+  c_we_p1   <= c_we;\r
+  c_addr_p1 <= c_addr;\r
+  c_di_p1   <= c_di;\r
+  if ( c_we_p1 ) begin\r
+    if ( nonrle_en == 1 ) begin\r
+      event_ram_array[c_addr_p1] <= c_di_p1;\r
+    end \r
+  end // if ( c_we )\r
+\r
+  dwords_3_0_p1   <= dwords_3_0[127:0];\r
+  dwords_7_4_p1   <= dwords_7_4[127:0];\r
+  dwords_11_8_p1  <= dwords_11_8[127:0];\r
+  dwords_15_12_p1 <= dwords_15_12[127:0];\r
+\r
+  dwords_3_0_p2   <= dwords_3_0_p1[127:0];\r
+  dwords_7_4_p2   <= dwords_7_4_p1[127:0];\r
+  dwords_11_8_p2  <= dwords_11_8_p1[127:0];\r
+  dwords_15_12_p2 <= dwords_15_12_p1[127:0];\r
+\r
+  if ( c_we_p1 ) begin\r
+    if ( data_dwords >= 4 ) begin\r
+      dwords_3_0_ram_array[ c_addr_p1 ]  <= dwords_3_0_p2[127:0];\r
+    end\r
+    if ( data_dwords >= 8 ) begin\r
+      dwords_7_4_ram_array[ c_addr_p1 ]  <= dwords_7_4_p2[127:0];\r
+    end\r
+    if ( data_dwords >= 12 ) begin\r
+      dwords_11_8_ram_array[ c_addr_p1 ] <= dwords_11_8_p2[127:0];\r
+    end\r
+    if ( data_dwords >= 16 ) begin\r
+      dwords_15_12_ram_array[ c_addr_p1 ] <= dwords_15_12_p2[127:0];\r
+    end\r
+  end // if ( c_we )\r
+end // always\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// 2nd Port of RAM is clocked from local bus\r
+//-----------------------------------------------------------------------------\r
+always @( posedge clk_lb )\r
+begin\r
+  if ( nonrle_en == 1 ) begin\r
+    d_do    <= event_ram_array[d_addr] ;\r
+  end\r
+\r
+  if ( data_dwords >= 4 ) begin\r
+    dwords_3_0_do   <= dwords_3_0_ram_array[ d_addr ];\r
+  end\r
+  if ( data_dwords >= 8 ) begin\r
+    dwords_7_4_do   <= dwords_7_4_ram_array[ d_addr ];\r
+  end\r
+  if ( data_dwords >= 12 ) begin\r
+    dwords_11_8_do  <= dwords_11_8_ram_array[ d_addr ];\r
+  end\r
+  if ( data_dwords >= 16 ) begin\r
+    dwords_15_12_do <= dwords_15_12_ram_array[ d_addr ];\r
+  end\r
+end // always\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// RLE Dual Port RAM - Infer RAM here to make easy to change depth on the fly\r
+//-----------------------------------------------------------------------------\r
+always @( posedge clk_cap  )\r
+begin\r
+  if ( rle_en == 1 ) begin\r
+    a_we_p1   <= a_we;\r
+    a_addr_p1 <= a_addr;\r
+    a_we_p1   <= a_we;\r
+    a_addr_p1 <= a_addr;\r
+    a_di_p1   <= a_di;\r
+//  if ( a_we_p1 ) begin\r
+//    rle_ram_array[a_addr_p1] <= a_di_p1;\r
+//  end // if ( a_we )\r
+    if ( a_we    ) begin\r
+      rle_ram_array[a_addr   ] <= a_di;\r
+    end // if ( a_we )\r
+  end\r
+end // always\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// 2nd Port of RAM is clocked from local bus\r
+//-----------------------------------------------------------------------------\r
+always @( posedge clk_lb )\r
+begin\r
+  if ( rle_en == 1 ) begin\r
+    b_do <= rle_ram_array[d_addr];\r
+  end\r
+end // always\r
+\r
+\r
+endmodule // sump2\r