660 lines
22 KiB
Verilog
660 lines
22 KiB
Verilog
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// Copyright (C) 2023 Analog Devices, Inc. All rights reserved.
|
|
//
|
|
// In this HDL repository, there are many different and unique modules, consisting
|
|
// of various HDL (Verilog or VHDL) components. The individual modules are
|
|
// developed independently, and may be accompanied by separate and unique license
|
|
// terms.
|
|
//
|
|
// The user should read each of these license terms, and understand the
|
|
// freedoms and responsibilities that he or she has by using this source/core.
|
|
//
|
|
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
// A PARTICULAR PURPOSE.
|
|
//
|
|
// Redistribution and use of source or resulting binaries, with or without modification
|
|
// of this file, are permitted under one of the following two license terms:
|
|
//
|
|
// 1. The GNU General Public License version 2 as published by the
|
|
// Free Software Foundation, which can be found in the top level directory
|
|
// of this repository (LICENSE_GPL2), and also online at:
|
|
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
|
|
//
|
|
// OR
|
|
//
|
|
// 2. An ADI specific BSD license, which can be found in the top level directory
|
|
// of this repository (LICENSE_ADIBSD), and also on-line at:
|
|
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
|
|
// This will allow to generate bit files and not release the source code,
|
|
// as long as it attaches to an ADI device.
|
|
//
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
`timescale 1ns/100ps
|
|
|
|
module axi_ad4858_cmos #(
|
|
|
|
parameter FPGA_TECHNOLOGY = 0,
|
|
parameter DELAY_REFCLK_FREQ = 200,
|
|
parameter IODELAY_ENABLE = 1,
|
|
parameter IODELAY_GROUP = "dev_if_delay_group",
|
|
parameter ACTIVE_LANE = 8'b11111111
|
|
) (
|
|
|
|
input rst,
|
|
input clk,
|
|
input [ 7:0] adc_enable,
|
|
input adc_crc_enable,
|
|
|
|
// physical interface
|
|
|
|
output scki,
|
|
input scko,
|
|
input [ 7:0] db_i,
|
|
input busy,
|
|
input cnvs,
|
|
|
|
// format
|
|
|
|
input [ 1:0] packet_format,
|
|
input oversampling_en,
|
|
|
|
// channel interface
|
|
|
|
output [255:0] adc_data,
|
|
output reg adc_valid,
|
|
output reg crc_error,
|
|
output [ 7:0] dev_status,
|
|
|
|
// delay interface (for IDELAY macros)
|
|
|
|
input up_clk,
|
|
input [ 7:0] up_adc_dld,
|
|
input [39:0] up_adc_dwdata,
|
|
output [39:0] up_adc_drdata,
|
|
input delay_clk,
|
|
input delay_rst,
|
|
output delay_locked
|
|
);
|
|
|
|
localparam NEG_EDGE = 1;
|
|
localparam DW = 32;
|
|
localparam BW = DW - 1;
|
|
localparam PACKET_1_BITS = 20;
|
|
localparam PACKET_2_BITS = 24;
|
|
localparam PACKET_3_BITS = 32;
|
|
|
|
// internal registers
|
|
|
|
reg [BW:0] adc_lane_0;
|
|
reg [BW:0] adc_lane_1;
|
|
reg [BW:0] adc_lane_2;
|
|
reg [BW:0] adc_lane_3;
|
|
reg [BW:0] adc_lane_4;
|
|
reg [BW:0] adc_lane_5;
|
|
reg [BW:0] adc_lane_6;
|
|
reg [BW:0] adc_lane_7;
|
|
|
|
reg [ 5:0] data_counter = 6'h0;
|
|
reg [ 5:0] scki_counter = 6'h0;
|
|
|
|
reg scki_i;
|
|
reg scki_d;
|
|
|
|
reg [BW:0] adc_data_store[8:0];
|
|
reg [BW:0] adc_data_init[7:0];
|
|
reg adc_valid_init;
|
|
reg adc_valid_init_d;
|
|
|
|
reg [ 8:0] ch_capture;
|
|
reg [ 8:0] ch_captured;
|
|
|
|
reg [ 4:0] adc_ch0_shift;
|
|
reg [ 4:0] adc_ch1_shift;
|
|
reg [ 4:0] adc_ch2_shift;
|
|
reg [ 4:0] adc_ch3_shift;
|
|
reg [ 4:0] adc_ch4_shift;
|
|
reg [ 4:0] adc_ch5_shift;
|
|
reg [ 4:0] adc_ch6_shift;
|
|
reg [ 4:0] adc_ch7_shift;
|
|
|
|
reg [ 4:0] adc_ch0_shift_d;
|
|
reg [ 4:0] adc_ch1_shift_d;
|
|
reg [ 4:0] adc_ch2_shift_d;
|
|
reg [ 4:0] adc_ch3_shift_d;
|
|
reg [ 4:0] adc_ch4_shift_d;
|
|
reg [ 4:0] adc_ch5_shift_d;
|
|
reg [ 4:0] adc_ch6_shift_d;
|
|
reg [ 4:0] adc_ch7_shift_d;
|
|
|
|
reg [ 3:0] lane_0_data = 'd0;
|
|
reg [ 3:0] lane_1_data = 'd0;
|
|
reg [ 3:0] lane_2_data = 'd0;
|
|
reg [ 3:0] lane_3_data = 'd0;
|
|
reg [ 3:0] lane_4_data = 'd0;
|
|
reg [ 3:0] lane_5_data = 'd0;
|
|
reg [ 3:0] lane_6_data = 'd0;
|
|
reg [ 3:0] lane_7_data = 'd0;
|
|
reg [ 8:0] ch_data_lock = 'h1ff;
|
|
|
|
reg busy_m1;
|
|
reg busy_m2;
|
|
reg cnvs_d;
|
|
reg [31:0] period_cnt;
|
|
|
|
reg conversion_quiet_time;
|
|
reg run_busy_period_cnt;
|
|
reg [31:0] busy_conversion_cnt;
|
|
reg [31:0] busy_measure_value;
|
|
reg start_transfer;
|
|
|
|
reg crc_enable_window;
|
|
reg run_crc;
|
|
reg run_crc_d;
|
|
reg [288:0] crc_data_in;
|
|
reg [15:0] crc_cnt;
|
|
reg [ 7:0] data_in_byte;
|
|
|
|
// internal wires
|
|
|
|
wire [ 7:0] db_s;
|
|
|
|
wire [31:0] status_and_crc_data;
|
|
|
|
wire aquire_data;
|
|
wire scki_cnt_rst;
|
|
wire adc_cnvs_redge;
|
|
wire conversion_completed;
|
|
wire conversion_quiet_time_s;
|
|
|
|
wire [ 5:0] packet_lenght;
|
|
|
|
wire crc_reset;
|
|
wire crc_enable;
|
|
wire crc_valid;
|
|
wire [15:0] crc_res;
|
|
wire [15:0] crc_data_lenght;
|
|
|
|
// packet format selection
|
|
|
|
assign packet_lenght = packet_format == 2'd0 ? 6'd20 :
|
|
packet_format == 2'd1 ? 6'd24 : 6'd32;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst == 1'b1) begin
|
|
busy_m1 <= 1'b0;
|
|
busy_m2 <= 1'b0;
|
|
start_transfer <= 1'b0;
|
|
end else begin
|
|
busy_m1 <= busy;
|
|
busy_m2 <= busy_m1;
|
|
start_transfer <= busy_m2 & !busy_m1;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (start_transfer) begin
|
|
crc_enable_window <= adc_crc_enable;
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
scki_counter <= 5'h0;
|
|
scki_i <= 1'b1;
|
|
scki_d <= 1'b0;
|
|
end else begin
|
|
scki_d <= scki_i;
|
|
if (aquire_data == 1'b0) begin
|
|
scki_counter <= 5'h0;
|
|
scki_i <= 1'b1;
|
|
end else if (scki_cnt_rst & (scki_d & ~scki_i)) begin // end of a capture
|
|
scki_counter <= 5'h1;
|
|
scki_i <= 1'b1;
|
|
end else if (scki_i == 1'b0) begin
|
|
scki_counter <= scki_counter + 1;
|
|
scki_i <= 1'b1;
|
|
end else if (conversion_quiet_time_s == 1'b1) begin
|
|
scki_counter <= scki_counter;
|
|
scki_i <= scki_i;
|
|
end else begin
|
|
scki_counter <= scki_counter;
|
|
scki_i <= ~scki_i;
|
|
end
|
|
end
|
|
end
|
|
|
|
// busy period counter
|
|
always @(posedge clk) begin
|
|
if (rst == 1'b1) begin
|
|
run_busy_period_cnt <= 1'b0;
|
|
busy_conversion_cnt <= 'd0;
|
|
busy_measure_value <= 'd0;
|
|
end else begin
|
|
if (cnvs == 1'b1 && busy_m2 == 1'b1) begin
|
|
run_busy_period_cnt <= 1'b1;
|
|
end else if (start_transfer == 1'b1) begin
|
|
run_busy_period_cnt <= 1'b0;
|
|
end
|
|
|
|
if (adc_cnvs_redge == 1'b1) begin
|
|
busy_conversion_cnt <= 'd0;
|
|
end else if (start_transfer == 1'b1) begin
|
|
busy_measure_value <= busy_conversion_cnt;
|
|
end else if (run_busy_period_cnt == 1'b1) begin
|
|
busy_conversion_cnt <= busy_conversion_cnt + 'd1;
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
period_cnt <= 'd0;
|
|
cnvs_d <= 'd0;
|
|
conversion_quiet_time <= 1'b0;
|
|
end else begin
|
|
cnvs_d <= cnvs;
|
|
if (oversampling_en == 1 && adc_cnvs_redge == 1'b1) begin
|
|
conversion_quiet_time <= 1'b1;
|
|
end else begin
|
|
conversion_quiet_time <= conversion_quiet_time & ~conversion_completed;
|
|
end
|
|
if (adc_cnvs_redge == 1'b1) begin
|
|
period_cnt <= 'd0;
|
|
end else begin
|
|
period_cnt <= period_cnt + 1;
|
|
end
|
|
end
|
|
end
|
|
|
|
assign conversion_quiet_time_s = (oversampling_en == 1) ? conversion_quiet_time | cnvs : 1'b0;
|
|
assign conversion_completed = (period_cnt == busy_measure_value) ? 1'b1 : 1'b0;
|
|
assign adc_cnvs_redge = ~cnvs_d & cnvs;
|
|
assign scki_cnt_rst = (scki_counter == packet_lenght) ? 1'b1 : 1'b0;
|
|
assign scki = scki_i | ~aquire_data;
|
|
|
|
/*
|
|
The device sends each channel data on one of the 8 lines.
|
|
Data is stored in the device in a ring buffer. After the first packet is read
|
|
and no new conversion is activated if the reading process restarted,
|
|
the new data on the lines will be from the next index from the ring buffer.
|
|
e.g For second read process without a conversion start
|
|
line 0 = channel 1, line 1 = channel 2, line 2 = channel 3; so on and so forth.
|
|
*/
|
|
|
|
always @(posedge clk) begin
|
|
if (start_transfer) begin
|
|
lane_0_data <= 4'd0;
|
|
lane_1_data <= 4'd1;
|
|
lane_2_data <= 4'd2;
|
|
lane_3_data <= 4'd3;
|
|
lane_4_data <= 4'd4;
|
|
lane_5_data <= 4'd5;
|
|
lane_6_data <= 4'd6;
|
|
lane_7_data <= 4'd7;
|
|
ch_data_lock <= 9'd0;
|
|
end else if (aquire_data == 1'b1 && (scki_cnt_rst & (~scki_d & scki_i))) begin
|
|
lane_0_data <= lane_0_data[3] == 1'b1 ? 4'd0 : lane_0_data + 1;
|
|
lane_1_data <= lane_1_data[3] == 1'b1 ? 4'd0 : lane_1_data + 1;
|
|
lane_2_data <= lane_2_data[3] == 1'b1 ? 4'd0 : lane_2_data + 1;
|
|
lane_3_data <= lane_3_data[3] == 1'b1 ? 4'd0 : lane_3_data + 1;
|
|
lane_4_data <= lane_4_data[3] == 1'b1 ? 4'd0 : lane_4_data + 1;
|
|
lane_5_data <= lane_5_data[3] == 1'b1 ? 4'd0 : lane_5_data + 1;
|
|
lane_6_data <= lane_6_data[3] == 1'b1 ? 4'd0 : lane_6_data + 1;
|
|
lane_7_data <= lane_7_data[3] == 1'b1 ? 4'd0 : lane_7_data + 1;
|
|
ch_data_lock[lane_0_data[3:0]] <= ACTIVE_LANE[0] ? 1'b1 : ch_data_lock[lane_0_data[2:0]];
|
|
ch_data_lock[lane_1_data[3:0]] <= ACTIVE_LANE[1] ? 1'b1 : ch_data_lock[lane_1_data[2:0]];
|
|
ch_data_lock[lane_2_data[3:0]] <= ACTIVE_LANE[2] ? 1'b1 : ch_data_lock[lane_2_data[2:0]];
|
|
ch_data_lock[lane_3_data[3:0]] <= ACTIVE_LANE[3] ? 1'b1 : ch_data_lock[lane_3_data[2:0]];
|
|
ch_data_lock[lane_4_data[3:0]] <= ACTIVE_LANE[4] ? 1'b1 : ch_data_lock[lane_4_data[2:0]];
|
|
ch_data_lock[lane_5_data[3:0]] <= ACTIVE_LANE[5] ? 1'b1 : ch_data_lock[lane_5_data[2:0]];
|
|
ch_data_lock[lane_6_data[3:0]] <= ACTIVE_LANE[6] ? 1'b1 : ch_data_lock[lane_6_data[2:0]];
|
|
ch_data_lock[lane_7_data[3:0]] <= ACTIVE_LANE[7] ? 1'b1 : ch_data_lock[lane_7_data[2:0]];
|
|
end else begin
|
|
lane_0_data <= lane_0_data;
|
|
lane_1_data <= lane_1_data;
|
|
lane_2_data <= lane_2_data;
|
|
lane_3_data <= lane_3_data;
|
|
lane_4_data <= lane_4_data;
|
|
lane_5_data <= lane_5_data;
|
|
lane_6_data <= lane_6_data;
|
|
lane_7_data <= lane_7_data;
|
|
ch_data_lock <= ch_data_lock;
|
|
end
|
|
end
|
|
|
|
assign aquire_data = ~((ch_data_lock[0] | ~adc_enable[0]) &
|
|
(ch_data_lock[1] | ~adc_enable[1]) &
|
|
(ch_data_lock[2] | ~adc_enable[2]) &
|
|
(ch_data_lock[3] | ~adc_enable[3]) &
|
|
(ch_data_lock[4] | ~adc_enable[4]) &
|
|
(ch_data_lock[5] | ~adc_enable[5]) &
|
|
(ch_data_lock[6] | ~adc_enable[6]) &
|
|
(ch_data_lock[7] | ~adc_enable[7]) &
|
|
(ch_data_lock[8] | ~crc_enable_window));
|
|
|
|
// capture data
|
|
|
|
genvar i;
|
|
generate
|
|
if (IODELAY_ENABLE == 1) begin
|
|
ad_data_in #(
|
|
.SINGLE_ENDED (1),
|
|
.DDR_SDR_N (0),
|
|
.FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
|
|
.IODELAY_CTRL (1),
|
|
.IODELAY_ENABLE (IODELAY_ENABLE),
|
|
.IODELAY_GROUP (IODELAY_GROUP),
|
|
.REFCLK_FREQUENCY (DELAY_REFCLK_FREQ)
|
|
) i_rx_data (
|
|
.rx_clk (scko),
|
|
.rx_data_in_p (db_i[0]),
|
|
.rx_data_in_n (1'd0),
|
|
.rx_data_p (db_s[0]),
|
|
.rx_data_n (),
|
|
.up_clk (up_clk),
|
|
.up_dld (up_adc_dld[0]),
|
|
.up_dwdata (up_adc_dwdata[4:0]),
|
|
.up_drdata (up_adc_drdata[4:0]),
|
|
.delay_clk (delay_clk),
|
|
.delay_rst (delay_rst),
|
|
.delay_locked (delay_locked));
|
|
end
|
|
for (i = 1; i < 8; i = i + 1) begin: g_rx_lanes
|
|
ad_data_in #(
|
|
.SINGLE_ENDED (1),
|
|
.DDR_SDR_N (0),
|
|
.FPGA_TECHNOLOGY (FPGA_TECHNOLOGY),
|
|
.IODELAY_CTRL (0),
|
|
.IODELAY_ENABLE (IODELAY_ENABLE),
|
|
.IODELAY_GROUP (IODELAY_GROUP),
|
|
.REFCLK_FREQUENCY (DELAY_REFCLK_FREQ)
|
|
) i_rx_data (
|
|
.rx_clk (scko),
|
|
.rx_data_in_p (db_i[i]),
|
|
.rx_data_in_n (1'd0),
|
|
.rx_data_p (db_s[i]),
|
|
.rx_data_n (),
|
|
.up_clk (up_clk),
|
|
.up_dld (up_adc_dld[i]),
|
|
.up_dwdata (up_adc_dwdata[((i*5)+4):(i*5)]),
|
|
.up_drdata (up_adc_drdata[((i*5)+4):(i*5)]),
|
|
.delay_clk (delay_clk),
|
|
.delay_rst (delay_rst),
|
|
.delay_locked ());
|
|
end
|
|
endgenerate
|
|
|
|
// the most significant bits of the adc_lane_x will remaind from the
|
|
// previous sample for packet formats other than 32.
|
|
|
|
always @(negedge scko) begin
|
|
adc_lane_0 <= {adc_lane_0[BW-1:0], db_s[0]};
|
|
adc_lane_1 <= {adc_lane_1[BW-1:0], db_s[1]};
|
|
adc_lane_2 <= {adc_lane_2[BW-1:0], db_s[2]};
|
|
adc_lane_3 <= {adc_lane_3[BW-1:0], db_s[3]};
|
|
adc_lane_4 <= {adc_lane_4[BW-1:0], db_s[4]};
|
|
adc_lane_5 <= {adc_lane_5[BW-1:0], db_s[5]};
|
|
adc_lane_6 <= {adc_lane_6[BW-1:0], db_s[6]};
|
|
adc_lane_7 <= {adc_lane_7[BW-1:0], db_s[7]};
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst == 1'b1) begin
|
|
adc_valid_init <= 1'b0;
|
|
end else begin
|
|
if (data_counter == packet_lenght && adc_valid_init == 1'b0) begin
|
|
adc_valid_init <= 1'b1;
|
|
end else begin
|
|
adc_valid_init <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst == 1'b1) begin
|
|
adc_data_init[0] <= 'h0;
|
|
adc_data_init[1] <= 'h0;
|
|
adc_data_init[2] <= 'h0;
|
|
adc_data_init[3] <= 'h0;
|
|
adc_data_init[4] <= 'h0;
|
|
adc_data_init[5] <= 'h0;
|
|
adc_data_init[6] <= 'h0;
|
|
adc_data_init[7] <= 'h0;
|
|
data_counter <= 'h0;
|
|
end else begin
|
|
data_counter <= scki_counter;
|
|
if (data_counter == packet_lenght) begin
|
|
adc_data_init[0] <= adc_lane_0;
|
|
adc_data_init[1] <= adc_lane_1;
|
|
adc_data_init[2] <= adc_lane_2;
|
|
adc_data_init[3] <= adc_lane_3;
|
|
adc_data_init[4] <= adc_lane_4;
|
|
adc_data_init[5] <= adc_lane_5;
|
|
adc_data_init[6] <= adc_lane_6;
|
|
adc_data_init[7] <= adc_lane_7;
|
|
end else begin
|
|
adc_data_init[0] <= adc_data_init[0];
|
|
adc_data_init[1] <= adc_data_init[1];
|
|
adc_data_init[2] <= adc_data_init[2];
|
|
adc_data_init[3] <= adc_data_init[3];
|
|
adc_data_init[4] <= adc_data_init[4];
|
|
adc_data_init[5] <= adc_data_init[5];
|
|
adc_data_init[6] <= adc_data_init[6];
|
|
adc_data_init[7] <= adc_data_init[7];
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst == 1'b1 || adc_valid == 1'b1) begin
|
|
adc_valid <= 1'b0;
|
|
adc_valid_init_d <= 1'b0;
|
|
ch_capture <= 9'd0;
|
|
ch_captured <= 9'd0;
|
|
|
|
adc_ch0_shift <= 4'd0;
|
|
adc_ch1_shift <= 4'd0;
|
|
adc_ch2_shift <= 4'd0;
|
|
adc_ch3_shift <= 4'd0;
|
|
adc_ch4_shift <= 4'd0;
|
|
adc_ch5_shift <= 4'd0;
|
|
adc_ch6_shift <= 4'd0;
|
|
adc_ch7_shift <= 4'd0;
|
|
adc_ch0_shift_d <= 4'd0;
|
|
adc_ch1_shift_d <= 4'd0;
|
|
adc_ch2_shift_d <= 4'd0;
|
|
adc_ch3_shift_d <= 4'd0;
|
|
adc_ch4_shift_d <= 4'd0;
|
|
adc_ch5_shift_d <= 4'd0;
|
|
adc_ch6_shift_d <= 4'd0;
|
|
adc_ch7_shift_d <= 4'd0;
|
|
end else begin
|
|
ch_capture <= ch_data_lock;
|
|
ch_captured <= ch_capture;
|
|
adc_valid_init_d <= adc_valid_init;
|
|
|
|
adc_ch0_shift <= {ACTIVE_LANE[0],lane_0_data};
|
|
adc_ch1_shift <= {ACTIVE_LANE[1],lane_1_data};
|
|
adc_ch2_shift <= {ACTIVE_LANE[2],lane_2_data};
|
|
adc_ch3_shift <= {ACTIVE_LANE[3],lane_3_data};
|
|
adc_ch4_shift <= {ACTIVE_LANE[4],lane_4_data};
|
|
adc_ch5_shift <= {ACTIVE_LANE[5],lane_5_data};
|
|
adc_ch6_shift <= {ACTIVE_LANE[6],lane_6_data};
|
|
adc_ch7_shift <= {ACTIVE_LANE[7],lane_7_data};
|
|
adc_ch0_shift_d <= adc_ch0_shift;
|
|
adc_ch1_shift_d <= adc_ch1_shift;
|
|
adc_ch2_shift_d <= adc_ch2_shift;
|
|
adc_ch3_shift_d <= adc_ch3_shift;
|
|
adc_ch4_shift_d <= adc_ch4_shift;
|
|
adc_ch5_shift_d <= adc_ch5_shift;
|
|
adc_ch6_shift_d <= adc_ch6_shift;
|
|
adc_ch7_shift_d <= adc_ch7_shift;
|
|
adc_valid <= adc_valid_init_d &
|
|
(ch_captured[0] | ~adc_enable[0]) &
|
|
(ch_captured[1] | ~adc_enable[1]) &
|
|
(ch_captured[2] | ~adc_enable[2]) &
|
|
(ch_captured[3] | ~adc_enable[3]) &
|
|
(ch_captured[4] | ~adc_enable[4]) &
|
|
(ch_captured[5] | ~adc_enable[5]) &
|
|
(ch_captured[6] | ~adc_enable[6]) &
|
|
(ch_captured[7] | ~adc_enable[7]) &
|
|
(ch_captured[8] | ~crc_enable_window);
|
|
end
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst == 1'b1) begin
|
|
adc_data_store[0] <= 'd0;
|
|
adc_data_store[1] <= 'd0;
|
|
adc_data_store[2] <= 'd0;
|
|
adc_data_store[3] <= 'd0;
|
|
adc_data_store[4] <= 'd0;
|
|
adc_data_store[5] <= 'd0;
|
|
adc_data_store[6] <= 'd0;
|
|
adc_data_store[7] <= 'd0;
|
|
adc_data_store[8] <= 'd0;
|
|
end else begin
|
|
if (!adc_valid_init_d & adc_valid_init) begin
|
|
if (adc_ch0_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch0_shift_d[3:0]] <= adc_data_init[0];
|
|
end
|
|
if (adc_ch1_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch1_shift_d[3:0]] <= adc_data_init[1];
|
|
end
|
|
if (adc_ch2_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch2_shift_d[3:0]] <= adc_data_init[2];
|
|
end
|
|
if (adc_ch3_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch3_shift_d[3:0]] <= adc_data_init[3];
|
|
end
|
|
if (adc_ch4_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch4_shift_d[3:0]] <= adc_data_init[4];
|
|
end
|
|
if (adc_ch5_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch5_shift_d[3:0]] <= adc_data_init[5];
|
|
end
|
|
if (adc_ch6_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch6_shift_d[3:0]] <= adc_data_init[6];
|
|
end
|
|
if (adc_ch7_shift_d[4] == 1'b1) begin
|
|
adc_data_store[adc_ch7_shift_d[3:0]] <= adc_data_init[7];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
assign dev_status = packet_format == 0 ? adc_data_store[8][23:16] << 4 :
|
|
adc_data_store[8][23:16];
|
|
assign crc_data = adc_data_store[8][15:0];
|
|
assign adc_data = {adc_data_store[7],
|
|
adc_data_store[6],
|
|
adc_data_store[5],
|
|
adc_data_store[4],
|
|
adc_data_store[3],
|
|
adc_data_store[2],
|
|
adc_data_store[1],
|
|
adc_data_store[0]};
|
|
|
|
// CRC checker logic
|
|
|
|
always @(posedge clk) begin
|
|
if (rst == 1) begin
|
|
crc_data_in <= 0;
|
|
end else begin
|
|
if (adc_valid == 1) begin
|
|
if (packet_format == 0) begin
|
|
crc_data_in <= {104'd0,
|
|
adc_data_store[0][19:0],
|
|
adc_data_store[1][19:0],
|
|
adc_data_store[2][19:0],
|
|
adc_data_store[3][19:0],
|
|
adc_data_store[4][19:0],
|
|
adc_data_store[5][19:0],
|
|
adc_data_store[6][19:0],
|
|
adc_data_store[7][19:0],
|
|
adc_data_store[8][19:0],
|
|
4'd0};
|
|
end else if (packet_format == 1) begin
|
|
crc_data_in <= {72'd0,
|
|
adc_data_store[0][23:0],
|
|
adc_data_store[1][23:0],
|
|
adc_data_store[2][23:0],
|
|
adc_data_store[3][23:0],
|
|
adc_data_store[4][23:0],
|
|
adc_data_store[5][23:0],
|
|
adc_data_store[6][23:0],
|
|
adc_data_store[7][23:0],
|
|
adc_data_store[8][23:0]};
|
|
end else begin
|
|
crc_data_in <= {adc_data_store[0],
|
|
adc_data_store[1],
|
|
adc_data_store[2],
|
|
adc_data_store[3],
|
|
adc_data_store[4],
|
|
adc_data_store[5],
|
|
adc_data_store[6],
|
|
adc_data_store[7],
|
|
adc_data_store[8]};
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
// As an optimization, a crc checker with 8 parallel operations per clk cycle
|
|
// will be used for all packet formats.
|
|
// The channel plus status and crc data will be feed in byte packets to the
|
|
// crc checker.
|
|
// When packet_format is 20 bits, 20x8+20(st and crc) = 180 which is not a
|
|
// multiple of 8. So, we will feed 184 bits, which is a multiple of 8.
|
|
// First extra 4 bits entering the checker being 0, will not affect the result
|
|
// since the initial value of the LFSR is 0x0000.
|
|
assign crc_data_lenght = packet_format == 2'd0 ? 16'd176 : // 184-8
|
|
packet_format == 2'd1 ? 16'd208 : 16'd280;
|
|
|
|
always @(posedge clk) begin
|
|
if (crc_enable_window == 0 || adc_valid == 1) begin
|
|
crc_cnt <= crc_data_lenght;
|
|
data_in_byte <= 0;
|
|
run_crc <= adc_valid;
|
|
end else begin
|
|
if (run_crc == 1'b1) begin
|
|
if (crc_cnt == 0) begin
|
|
run_crc <= 1'b0;
|
|
end else begin
|
|
crc_cnt <= crc_cnt - 8;
|
|
end
|
|
data_in_byte <= crc_data_in[crc_cnt +: 8];
|
|
end else begin
|
|
end
|
|
end
|
|
// the counter is initialized with n-1 to accommodate the byte shifter
|
|
run_crc_d <= run_crc;
|
|
end
|
|
|
|
assign crc_reset = adc_valid;
|
|
assign crc_enable = run_crc | run_crc_d;
|
|
|
|
always @(posedge clk) begin
|
|
if (crc_valid == 1) begin
|
|
if (crc_res == 16'd0) begin
|
|
crc_error <= 1'd0;
|
|
end else begin
|
|
crc_error <= 1'd1;
|
|
end
|
|
end
|
|
end
|
|
|
|
axi_ad4858_crc i_ad4858_crc_8 (
|
|
.rst (crc_reset),
|
|
.clk (clk),
|
|
.crc_en (crc_enable),
|
|
.d_in (data_in_byte),
|
|
.crc_valid (crc_valid),
|
|
.crc_res (crc_res));
|
|
|
|
endmodule
|