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
parent
d2b1164567
commit
2e0ba5bffd
|
@ -35,11 +35,7 @@
|
|||
|
||||
`timescale 1ns/100ps
|
||||
|
||||
module axi_logic_analyzer #(
|
||||
|
||||
// add sample delays on LA to compensate for adc path delay
|
||||
|
||||
parameter ADC_PATH_DELAY = 19) (
|
||||
module axi_logic_analyzer (
|
||||
|
||||
// interface
|
||||
|
||||
|
@ -58,6 +54,9 @@ module axi_logic_analyzer #(
|
|||
input dac_valid,
|
||||
output reg dac_read,
|
||||
|
||||
input [ 2:0] external_rate,
|
||||
input external_valid,
|
||||
input external_decimation_en,
|
||||
input trigger_in,
|
||||
output trigger_out,
|
||||
output trigger_out_adc,
|
||||
|
@ -128,6 +127,40 @@ module axi_logic_analyzer #(
|
|||
|
||||
reg [15:0] adc_data_mn = '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
|
||||
|
||||
|
@ -181,6 +214,11 @@ module axi_logic_analyzer #(
|
|||
|
||||
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;
|
||||
|
||||
// signal name changes
|
||||
|
@ -189,9 +227,10 @@ module axi_logic_analyzer #(
|
|||
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_delayed = delay_counter == 32'h0 ? 1 : 0;
|
||||
|
||||
always @(posedge clk_out) begin
|
||||
always @(posedge clk_out) begin
|
||||
if (trigger_delay == 0) begin
|
||||
if (streaming == 1'b1 && sample_valid_la == 1'b1 && trigger_out_holdoff == 1'b1) begin
|
||||
streaming_on <= 1'b1;
|
||||
|
@ -208,7 +247,7 @@ module axi_logic_analyzer #(
|
|||
end
|
||||
|
||||
|
||||
always @(posedge clk_out) begin
|
||||
always @(posedge clk_out) begin
|
||||
if (sample_valid_la == 1'b1 && trigger_out_holdoff == 1'b1) begin
|
||||
up_triggered_set <= 1'b1;
|
||||
end else if (up_triggered_reset == 1'b1) begin
|
||||
|
@ -254,41 +293,92 @@ module axi_logic_analyzer #(
|
|||
|
||||
// - synchronization
|
||||
// - compensate for m2k adc path delay
|
||||
// - transfer data at clock frequency if capture is enabled
|
||||
|
||||
genvar j;
|
||||
|
||||
generate
|
||||
|
||||
reg [15:0] data_m[ADC_PATH_DELAY-2:0];
|
||||
|
||||
always @(posedge clk_out) begin
|
||||
if (sample_valid_la == 1'b1) begin
|
||||
data_m[0] <= data_i;
|
||||
end
|
||||
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
|
||||
|
||||
for (j = 0; j < ADC_PATH_DELAY - 2; j = j + 1) begin
|
||||
always @(posedge clk_out) begin
|
||||
if (sample_valid_la == 1'b1) begin
|
||||
data_m[j+1] <= data_m[j];
|
||||
end
|
||||
end
|
||||
end
|
||||
// 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
|
||||
|
||||
always @(posedge clk_out) begin
|
||||
if (sample_valid_la == 1'b1) begin
|
||||
adc_data_mn <= data_m[ADC_PATH_DELAY-2];
|
||||
adc_data <= adc_data_mn;
|
||||
end
|
||||
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
|
||||
if (sample_valid_la == 1'b1) begin
|
||||
case (in_data_delay)
|
||||
5'd0: adc_data_mn <= data_m_16;
|
||||
5'd1: adc_data_mn <= data_m_17;
|
||||
5'd2: adc_data_mn <= data_m_18;
|
||||
5'd3: adc_data_mn <= data_m_19;
|
||||
5'd4: adc_data_mn <= data_m_20;
|
||||
5'd5: adc_data_mn <= data_m_21;
|
||||
5'd6: adc_data_mn <= data_m_22;
|
||||
5'd7: adc_data_mn <= data_m_23;
|
||||
5'd8: adc_data_mn <= data_m_24;
|
||||
5'd9: adc_data_mn <= data_m_25;
|
||||
5'd10: adc_data_mn <= data_m_26;
|
||||
5'd11: adc_data_mn <= data_m_27;
|
||||
5'd12: adc_data_mn <= data_m_28;
|
||||
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;
|
||||
end
|
||||
endgenerate
|
||||
end
|
||||
|
||||
assign adc_valid = sample_valid_la;
|
||||
|
||||
always @(posedge clk_out) begin
|
||||
trigger_m1 <= trigger_i;
|
||||
end
|
||||
|
||||
// downsampler logic analyzer
|
||||
|
||||
always @(posedge clk_out) begin
|
||||
|
@ -296,7 +386,10 @@ module axi_logic_analyzer #(
|
|||
sample_valid_la <= 1'b0;
|
||||
downsampler_counter_la <= 32'h0;
|
||||
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;
|
||||
sample_valid_la <= 1'b0;
|
||||
end else begin
|
||||
|
@ -404,7 +497,6 @@ module axi_logic_analyzer #(
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
axi_logic_analyzer_trigger i_trigger (
|
||||
.clk (clk_out),
|
||||
.reset (reset),
|
||||
|
@ -446,11 +538,10 @@ module axi_logic_analyzer #(
|
|||
.overwrite_data (overwrite_data),
|
||||
.input_data (adc_data_mn),
|
||||
.od_pp_n (od_pp_n),
|
||||
|
||||
.triggered (up_triggered),
|
||||
.pg_trigger_config (pg_trigger_config),
|
||||
|
||||
.streaming(streaming),
|
||||
.data_delay_control (data_delay_control),
|
||||
|
||||
// bus interface
|
||||
|
||||
|
|
|
@ -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_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_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 =~ *data_m* && IS_SEQUENTIAL}]
|
||||
set_false_path -to [get_cells -hier -filter {name =~ *up_sync_ack_m* && IS_SEQUENTIAL}]
|
||||
|
||||
|
|
|
@ -62,8 +62,8 @@ module axi_logic_analyzer_reg (
|
|||
output [19:0] pg_trigger_config,
|
||||
|
||||
input triggered,
|
||||
|
||||
output streaming,
|
||||
output [ 9:0] data_delay_control,
|
||||
|
||||
// bus interface
|
||||
|
||||
|
@ -102,6 +102,7 @@ module axi_logic_analyzer_reg (
|
|||
reg [19:0] up_pg_trigger_config = 20'h0;
|
||||
reg up_triggered = 0;
|
||||
reg up_streaming = 0;
|
||||
reg [ 9:0] up_data_delay_control = 10'd0;
|
||||
|
||||
wire [15:0] up_input_data;
|
||||
|
||||
|
@ -128,6 +129,7 @@ module axi_logic_analyzer_reg (
|
|||
up_streaming <= 1'd0;
|
||||
up_trigger_holdoff <= 32'h0;
|
||||
up_pg_trigger_config <= 20'd0;
|
||||
up_data_delay_control <= 10'h0;
|
||||
end else begin
|
||||
up_wack <= up_wreq;
|
||||
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
|
||||
up_pg_trigger_config <= up_wdata[19:0];
|
||||
end
|
||||
if ((up_wreq == 1'b1) && (up_waddr[4:0] == 5'h16)) begin
|
||||
up_data_delay_control <= up_wdata[9:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -227,6 +232,7 @@ module axi_logic_analyzer_reg (
|
|||
5'h13: up_rdata <= {31'h0,up_streaming};
|
||||
5'h14: up_rdata <= up_trigger_holdoff;
|
||||
5'h15: up_rdata <= {12'h0,up_pg_trigger_config};
|
||||
5'h16: up_rdata <= {22'h0,up_data_delay_control};
|
||||
default: up_rdata <= 0;
|
||||
endcase
|
||||
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));
|
||||
|
||||
up_xfer_cntrl #(.DATA_WIDTH(343)) i_xfer_cntrl (
|
||||
up_xfer_cntrl #(.DATA_WIDTH(353)) i_xfer_cntrl (
|
||||
.up_rstn (up_rstn),
|
||||
.up_clk (up_clk),
|
||||
.up_data_cntrl ({ up_streaming, // 1
|
||||
|
@ -257,7 +263,8 @@ module axi_logic_analyzer_reg (
|
|||
up_io_selection, // 16
|
||||
up_pg_trigger_config, // 20
|
||||
up_divider_counter_pg, // 32
|
||||
up_divider_counter_la}), // 32
|
||||
up_divider_counter_la, // 32
|
||||
up_data_delay_control}), // 10
|
||||
|
||||
.up_xfer_done (),
|
||||
.d_rst (1'b0),
|
||||
|
@ -279,7 +286,8 @@ module axi_logic_analyzer_reg (
|
|||
io_selection, // 16
|
||||
pg_trigger_config, // 20
|
||||
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 (
|
||||
|
||||
|
|
Loading…
Reference in New Issue