axi_logic_analyzer: Auto sync to ADC path

The number of delay taps in the LA data path can be controlled manually, from
the regmap or automatically, according to the axi_adc_decimate's rate.

Moreover, because the rate is configure by software, and the time of
initialization, is different for the ADC path and LA path. There is an
uncertainty of plus/minus one sample between the two. Because ADC and LA
paths share the same clock we can easily synchronize the two paths. We
can't use reset, because the rate generation mechanism is different
between the two. So the ADC path is used as master valid generator and we
can use it to drive the LA path.
The synchronization is done by setting the rate source bit. This
mechanism can only be used if the desired rate for both path is equal,
including oversampling fom ADC decimation.
main
AndreiGrozav 2020-04-27 12:55:25 +03:00 committed by AndreiGrozav
parent d2b1164567
commit 2e0ba5bffd
3 changed files with 143 additions and 39 deletions

View File

@ -35,11 +35,7 @@
`timescale 1ns/100ps `timescale 1ns/100ps
module axi_logic_analyzer #( module axi_logic_analyzer (
// add sample delays on LA to compensate for adc path delay
parameter ADC_PATH_DELAY = 19) (
// interface // interface
@ -58,6 +54,9 @@ module axi_logic_analyzer #(
input dac_valid, input dac_valid,
output reg dac_read, output reg dac_read,
input [ 2:0] external_rate,
input external_valid,
input external_decimation_en,
input trigger_in, input trigger_in,
output trigger_out, output trigger_out,
output trigger_out_adc, output trigger_out_adc,
@ -128,6 +127,40 @@ module axi_logic_analyzer #(
reg [15:0] adc_data_mn = 'd0; reg [15:0] adc_data_mn = 'd0;
reg [31:0] trigger_holdoff_counter = 32'd0; reg [31:0] trigger_holdoff_counter = 32'd0;
reg [ 4:0] adc_data_delay = 5'd0;
reg [15:0] data_m_0;
reg [15:0] data_m_1;
reg [15:0] data_m_2;
reg [15:0] data_m_3;
reg [15:0] data_m_4;
reg [15:0] data_m_5;
reg [15:0] data_m_6;
reg [15:0] data_m_7;
reg [15:0] data_m_8;
reg [15:0] data_m_9;
reg [15:0] data_m_10;
reg [15:0] data_m_11;
reg [15:0] data_m_12;
reg [15:0] data_m_13;
reg [15:0] data_m_14;
reg [15:0] data_m_15;
reg [15:0] data_m_16;
reg [15:0] data_m_17;
reg [15:0] data_m_18;
reg [15:0] data_m_19;
reg [15:0] data_m_20;
reg [15:0] data_m_21;
reg [15:0] data_m_22;
reg [15:0] data_m_23;
reg [15:0] data_m_24;
reg [15:0] data_m_25;
reg [15:0] data_m_26;
reg [15:0] data_m_27;
reg [15:0] data_m_28;
reg [15:0] data_m_29;
reg [15:0] data_m_30;
reg [15:0] data_m_31;
// internal signals // internal signals
@ -181,6 +214,11 @@ module axi_logic_analyzer #(
wire streaming; wire streaming;
wire [ 4:0] in_data_delay;
wire [ 4:0] up_data_delay;
wire master_delay_ctrl;
wire [ 9:0] data_delay_control;
genvar i; genvar i;
// signal name changes // signal name changes
@ -189,6 +227,7 @@ module axi_logic_analyzer #(
assign up_rstn = s_axi_aresetn; assign up_rstn = s_axi_aresetn;
assign trigger_out = trigger_delay == 32'h0 ? trigger_out_holdoff | streaming_on : trigger_out_delayed | streaming_on; assign trigger_out = trigger_delay == 32'h0 ? trigger_out_holdoff | streaming_on : trigger_out_delayed | streaming_on;
assign trigger_out_delayed = delay_counter == 32'h0 ? 1 : 0; assign trigger_out_delayed = delay_counter == 32'h0 ? 1 : 0;
always @(posedge clk_out) begin always @(posedge clk_out) begin
@ -254,41 +293,92 @@ module axi_logic_analyzer #(
// - synchronization // - synchronization
// - compensate for m2k adc path delay // - compensate for m2k adc path delay
// - transfer data at clock frequency if capture is enabled
genvar j; always @(posedge clk_out) begin
data_m_0 <= data_i;
data_m_1 <= data_m_0;
data_m_2 <= data_m_1;
data_m_3 <= data_m_2;
data_m_4 <= data_m_3;
data_m_5 <= data_m_4;
data_m_6 <= data_m_5;
data_m_7 <= data_m_6;
data_m_8 <= data_m_7;
data_m_9 <= data_m_8;
data_m_10 <= data_m_9;
data_m_11 <= data_m_10;
data_m_12 <= data_m_11;
data_m_13 <= data_m_12;
data_m_14 <= data_m_13;
data_m_15 <= data_m_14;
data_m_16 <= data_m_15;
if (sample_valid_la == 1'b1) begin
data_m_17 <= data_m_16;
data_m_18 <= data_m_17;
data_m_19 <= data_m_18;
data_m_20 <= data_m_19;
data_m_21 <= data_m_20;
data_m_22 <= data_m_21;
data_m_23 <= data_m_22;
data_m_24 <= data_m_23;
data_m_25 <= data_m_24;
data_m_26 <= data_m_25;
data_m_27 <= data_m_26;
data_m_28 <= data_m_27;
data_m_29 <= data_m_28;
data_m_30 <= data_m_29;
data_m_31 <= data_m_30;
end
end
generate // adc path 'rate delay' given by axi_adc_decimate
always @(posedge clk_out) begin
case (external_rate)
3'd0: adc_data_delay <= 5'd1; // 100MSPS
3'd1: adc_data_delay <= 5'd3; // 10MSPS
default: adc_data_delay <= 5'd1; // <= 1MSPS
endcase
end
reg [15:0] data_m[ADC_PATH_DELAY-2:0]; assign up_data_delay = data_delay_control[4:0];
assign rate_gen_select = data_delay_control[8];
// select if the delay taps number is chosen by the user or automatically
assign master_delay_ctrl = data_delay_control[9];
assign in_data_delay = master_delay_ctrl ? up_data_delay :
external_decimation_en ? 5'd0 : adc_data_delay;
always @(posedge clk_out) begin always @(posedge clk_out) begin
if (sample_valid_la == 1'b1) begin if (sample_valid_la == 1'b1) begin
data_m[0] <= data_i; case (in_data_delay)
end 5'd0: adc_data_mn <= data_m_16;
end 5'd1: adc_data_mn <= data_m_17;
5'd2: adc_data_mn <= data_m_18;
for (j = 0; j < ADC_PATH_DELAY - 2; j = j + 1) begin 5'd3: adc_data_mn <= data_m_19;
always @(posedge clk_out) begin 5'd4: adc_data_mn <= data_m_20;
if (sample_valid_la == 1'b1) begin 5'd5: adc_data_mn <= data_m_21;
data_m[j+1] <= data_m[j]; 5'd6: adc_data_mn <= data_m_22;
end 5'd7: adc_data_mn <= data_m_23;
end 5'd8: adc_data_mn <= data_m_24;
end 5'd9: adc_data_mn <= data_m_25;
5'd10: adc_data_mn <= data_m_26;
always @(posedge clk_out) begin 5'd11: adc_data_mn <= data_m_27;
if (sample_valid_la == 1'b1) begin 5'd12: adc_data_mn <= data_m_28;
adc_data_mn <= data_m[ADC_PATH_DELAY-2]; 5'd13: adc_data_mn <= data_m_29;
5'd14: adc_data_mn <= data_m_30;
5'd15: adc_data_mn <= data_m_31;
default: adc_data_mn <= data_m_16;
endcase
adc_data <= adc_data_mn; adc_data <= adc_data_mn;
end end
end end
endgenerate
assign adc_valid = sample_valid_la; assign adc_valid = sample_valid_la;
always @(posedge clk_out) begin always @(posedge clk_out) begin
trigger_m1 <= trigger_i; trigger_m1 <= trigger_i;
end end
// downsampler logic analyzer // downsampler logic analyzer
always @(posedge clk_out) begin always @(posedge clk_out) begin
@ -296,7 +386,10 @@ module axi_logic_analyzer #(
sample_valid_la <= 1'b0; sample_valid_la <= 1'b0;
downsampler_counter_la <= 32'h0; downsampler_counter_la <= 32'h0;
end else begin end else begin
if (downsampler_counter_la < divider_counter_la ) begin if (rate_gen_select) begin
downsampler_counter_la <= 32'h0;
sample_valid_la <= external_valid;
end else if (downsampler_counter_la < divider_counter_la ) begin
downsampler_counter_la <= downsampler_counter_la + 1; downsampler_counter_la <= downsampler_counter_la + 1;
sample_valid_la <= 1'b0; sample_valid_la <= 1'b0;
end else begin end else begin
@ -404,7 +497,6 @@ module axi_logic_analyzer #(
end end
end end
axi_logic_analyzer_trigger i_trigger ( axi_logic_analyzer_trigger i_trigger (
.clk (clk_out), .clk (clk_out),
.reset (reset), .reset (reset),
@ -446,11 +538,10 @@ module axi_logic_analyzer #(
.overwrite_data (overwrite_data), .overwrite_data (overwrite_data),
.input_data (adc_data_mn), .input_data (adc_data_mn),
.od_pp_n (od_pp_n), .od_pp_n (od_pp_n),
.triggered (up_triggered), .triggered (up_triggered),
.pg_trigger_config (pg_trigger_config), .pg_trigger_config (pg_trigger_config),
.streaming(streaming), .streaming(streaming),
.data_delay_control (data_delay_control),
// bus interface // bus interface

View File

@ -1,7 +1,12 @@
set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *up_triggered_d*}] set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *up_triggered_d*}]
set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *up_triggered_reset_d*}] set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *up_triggered_reset_d*}]
set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *data_m*}]
set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *up_sync_ack_m*}]
set_false_path -to [get_pins BUFGMUX_CTRL_inst/S*] set_false_path -to [get_pins BUFGMUX_CTRL_inst/S*]
set_false_path -to [get_cells -hier -filter {name =~ *up_triggered_d1* && IS_SEQUENTIAL}] set_false_path -to [get_cells -hier -filter {name =~ *up_triggered_d1* && IS_SEQUENTIAL}]
set_false_path -to [get_cells -hier -filter {name =~ *up_triggered_reset_d1* && IS_SEQUENTIAL}] set_false_path -to [get_cells -hier -filter {name =~ *up_triggered_reset_d1* && IS_SEQUENTIAL}]
set_false_path -to [get_cells -hier -filter {name =~ *data_m* && IS_SEQUENTIAL}]
set_false_path -to [get_cells -hier -filter {name =~ *up_sync_ack_m* && IS_SEQUENTIAL}]

View File

@ -62,8 +62,8 @@ module axi_logic_analyzer_reg (
output [19:0] pg_trigger_config, output [19:0] pg_trigger_config,
input triggered, input triggered,
output streaming, output streaming,
output [ 9:0] data_delay_control,
// bus interface // bus interface
@ -102,6 +102,7 @@ module axi_logic_analyzer_reg (
reg [19:0] up_pg_trigger_config = 20'h0; reg [19:0] up_pg_trigger_config = 20'h0;
reg up_triggered = 0; reg up_triggered = 0;
reg up_streaming = 0; reg up_streaming = 0;
reg [ 9:0] up_data_delay_control = 10'd0;
wire [15:0] up_input_data; wire [15:0] up_input_data;
@ -128,6 +129,7 @@ module axi_logic_analyzer_reg (
up_streaming <= 1'd0; up_streaming <= 1'd0;
up_trigger_holdoff <= 32'h0; up_trigger_holdoff <= 32'h0;
up_pg_trigger_config <= 20'd0; up_pg_trigger_config <= 20'd0;
up_data_delay_control <= 10'h0;
end else begin end else begin
up_wack <= up_wreq; up_wack <= up_wreq;
if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h1)) begin if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h1)) begin
@ -192,6 +194,9 @@ module axi_logic_analyzer_reg (
if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h15)) begin if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h15)) begin
up_pg_trigger_config <= up_wdata[19:0]; up_pg_trigger_config <= up_wdata[19:0];
end end
if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h16)) begin
up_data_delay_control <= up_wdata[9:0];
end
end end
end end
@ -227,6 +232,7 @@ module axi_logic_analyzer_reg (
5'h13: up_rdata <= {31'h0,up_streaming}; 5'h13: up_rdata <= {31'h0,up_streaming};
5'h14: up_rdata <= up_trigger_holdoff; 5'h14: up_rdata <= up_trigger_holdoff;
5'h15: up_rdata <= {12'h0,up_pg_trigger_config}; 5'h15: up_rdata <= {12'h0,up_pg_trigger_config};
5'h16: up_rdata <= {22'h0,up_data_delay_control};
default: up_rdata <= 0; default: up_rdata <= 0;
endcase endcase
end else begin end else begin
@ -237,7 +243,7 @@ module axi_logic_analyzer_reg (
ad_rst i_core_rst_reg (.rst_async(~up_rstn), .clk(clk), .rstn(), .rst(reset)); ad_rst i_core_rst_reg (.rst_async(~up_rstn), .clk(clk), .rstn(), .rst(reset));
up_xfer_cntrl #(.DATA_WIDTH(343)) i_xfer_cntrl ( up_xfer_cntrl #(.DATA_WIDTH(353)) i_xfer_cntrl (
.up_rstn (up_rstn), .up_rstn (up_rstn),
.up_clk (up_clk), .up_clk (up_clk),
.up_data_cntrl ({ up_streaming, // 1 .up_data_cntrl ({ up_streaming, // 1
@ -257,7 +263,8 @@ module axi_logic_analyzer_reg (
up_io_selection, // 16 up_io_selection, // 16
up_pg_trigger_config, // 20 up_pg_trigger_config, // 20
up_divider_counter_pg, // 32 up_divider_counter_pg, // 32
up_divider_counter_la}), // 32 up_divider_counter_la, // 32
up_data_delay_control}), // 10
.up_xfer_done (), .up_xfer_done (),
.d_rst (1'b0), .d_rst (1'b0),
@ -279,7 +286,8 @@ module axi_logic_analyzer_reg (
io_selection, // 16 io_selection, // 16
pg_trigger_config, // 20 pg_trigger_config, // 20
divider_counter_pg, // 32 divider_counter_pg, // 32
divider_counter_la})); // 32 divider_counter_la, // 32
data_delay_control})); // 10
up_xfer_status #(.DATA_WIDTH(16)) i_xfer_status ( up_xfer_status #(.DATA_WIDTH(16)) i_xfer_status (