pluto_hdl_adi/library/axi_ad4858/axi_ad4858_cmos.v

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/main/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