--- /dev/null
+/* ****************************************************************************\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