initial commit, add dds_par module

This commit is contained in:
2024-01-15 09:36:08 +08:00
commit 315a673005
1374 changed files with 465956 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
###############################################################################
## Copyright (C) 2018-2023 Analog Devices, Inc.
### SPDX short identifier: BSD-1-Clause
## Auto-generated, do not modify!
###############################################################################
LIBRARY_NAME := axi_ltc235x
GENERIC_DEPS += ../common/ad_rst.v
GENERIC_DEPS += ../common/up_adc_channel.v
GENERIC_DEPS += ../common/up_adc_common.v
GENERIC_DEPS += ../common/up_axi.v
GENERIC_DEPS += ../common/up_clock_mon.v
GENERIC_DEPS += ../common/up_xfer_cntrl.v
GENERIC_DEPS += ../common/up_xfer_status.v
GENERIC_DEPS += axi_ltc235x.v
GENERIC_DEPS += axi_ltc235x_cmos.v
GENERIC_DEPS += axi_ltc235x_lvds.v
INTEL_DEPS += ../intel/common/up_clock_mon_constr.sdc
INTEL_DEPS += ../intel/common/up_rst_constr.sdc
INTEL_DEPS += ../intel/common/up_xfer_cntrl_constr.sdc
INTEL_DEPS += ../intel/common/up_xfer_status_constr.sdc
INTEL_DEPS += axi_ltc235x_hw.tcl
include ../scripts/library.mk
+512
View File
@@ -0,0 +1,512 @@
// ***************************************************************************
// ***************************************************************************
// 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_ltc235x #(
parameter ID = 0,
parameter XILINX_INTEL_N = 0,
parameter FPGA_TECHNOLOGY = 0,
parameter FPGA_FAMILY = 0,
parameter SPEED_GRADE = 0,
parameter DEV_PACKAGE = 0,
parameter LVDS_CMOS_N = 0,
parameter LANE_0_ENABLE = 1,
parameter LANE_1_ENABLE = 1,
parameter LANE_2_ENABLE = 1,
parameter LANE_3_ENABLE = 1,
parameter LANE_4_ENABLE = 1,
parameter LANE_5_ENABLE = 1,
parameter LANE_6_ENABLE = 1,
parameter LANE_7_ENABLE = 1,
parameter EXTERNAL_CLK = 0,
parameter LTC235X_FAMILY = 0,
parameter NUM_CHANNELS = 8,
parameter DATA_WIDTH = 18
) (
// physical data interface
input external_clk,
// common
input busy,
output lvds_cmos_n,
// cmos
output sdi,
output scki,
input scko,
input [ 7:0] sdo,
// lvds
output sdi_p,
output sdi_n,
output scki_p,
output scki_n,
input scko_p,
input scko_n,
input sdo_p,
input sdo_n,
// AXI Slave Memory Map
input s_axi_aclk,
input s_axi_aresetn,
input s_axi_awvalid,
input [15:0] s_axi_awaddr,
input [ 2:0] s_axi_awprot,
output s_axi_awready,
input s_axi_wvalid,
input [31:0] s_axi_wdata,
input [ 3:0] s_axi_wstrb,
output s_axi_wready,
output s_axi_bvalid,
output [ 1:0] s_axi_bresp,
input s_axi_bready,
input s_axi_arvalid,
input [15:0] s_axi_araddr,
input [ 2:0] s_axi_arprot,
output s_axi_arready,
output s_axi_rvalid,
output [ 1:0] s_axi_rresp,
output [31:0] s_axi_rdata,
input s_axi_rready,
// Write FIFO interface
input adc_dovf,
output adc_valid_0,
output adc_valid_1,
output adc_valid_2,
output adc_valid_3,
output adc_valid_4,
output adc_valid_5,
output adc_valid_6,
output adc_valid_7,
output adc_enable_0,
output adc_enable_1,
output adc_enable_2,
output adc_enable_3,
output adc_enable_4,
output adc_enable_5,
output adc_enable_6,
output adc_enable_7,
output [31:0] adc_data_0,
output [31:0] adc_data_1,
output [31:0] adc_data_2,
output [31:0] adc_data_3,
output [31:0] adc_data_4,
output [31:0] adc_data_5,
output [31:0] adc_data_6,
output [31:0] adc_data_7
);
// localparam
localparam [ 7:0] ACTIVE_LANES = {
LANE_7_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_6_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_5_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_4_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_3_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_2_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_1_ENABLE == 1 ? 1'b1 : 1'b0,
LANE_0_ENABLE == 1 ? 1'b1 : 1'b0};
localparam [ 0:0] RD_RAW_DATA = 1'b1;
localparam [ 0:0] CMOS_OR_LVDS_N = ~LVDS_CMOS_N[0];
localparam [31:0] CONFIG = {18'd0, RD_RAW_DATA, 5'b0, CMOS_OR_LVDS_N, 7'b0}; // truncated value with size 45 to match size of target (32)
// internal registers
reg up_wack = 1'b0;
reg up_rack = 1'b0;
reg [31:0] up_rdata = 32'b0;
// internal signals
wire [23:0] softspan_24;
wire [ 2:0] softspan_3[0:7];
wire adc_valid;
wire up_clk;
wire up_rstn;
wire up_rreq_s;
wire [13:0] up_raddr_s;
wire up_wreq_s;
wire [13:0] up_waddr_s;
wire adc_clk_s;
wire [13:0] up_addr_s;
wire [31:0] up_wdata_s;
wire [31:0] up_rdata_s[0:8];
wire [ 8:0] up_rack_s;
wire [ 8:0] up_wack_s;
// read raw, feature
wire rd_req_s;
wire wr_req_s;
wire [15:0] wr_data_s;
wire [15:0] rd_data_s;
wire rd_valid_s;
wire adc_rst_s;
wire [ 7:0] adc_enable;
wire [ 2:0] adc_status_header[0:7];
wire [31:0] adc_data[0:7];
// defaults
assign up_clk = s_axi_aclk;
assign up_rstn = s_axi_aresetn;
assign lvds_cmos_n = LVDS_CMOS_N[0];
assign adc_valid_0 = adc_valid;
assign adc_valid_1 = adc_valid;
assign adc_valid_2 = adc_valid;
assign adc_valid_3 = adc_valid;
assign adc_valid_4 = adc_valid;
assign adc_valid_5 = adc_valid;
assign adc_valid_6 = adc_valid;
assign adc_valid_7 = adc_valid;
assign adc_enable_0 = adc_enable[0];
assign adc_enable_1 = adc_enable[1];
assign adc_enable_2 = adc_enable[2];
assign adc_enable_3 = adc_enable[3];
assign adc_enable_4 = adc_enable[4];
assign adc_enable_5 = adc_enable[5];
assign adc_enable_6 = adc_enable[6];
assign adc_enable_7 = adc_enable[7];
assign adc_data_0 = adc_data[0];
assign adc_data_1 = adc_data[1];
assign adc_data_2 = adc_data[2];
assign adc_data_3 = adc_data[3];
assign adc_data_4 = adc_data[4];
assign adc_data_5 = adc_data[5];
assign adc_data_6 = adc_data[6];
assign adc_data_7 = adc_data[7];
generate
if (NUM_CHANNELS == 8) begin
assign softspan_24 = {softspan_3[7], softspan_3[6], softspan_3[5], softspan_3[4], softspan_3[3], softspan_3[2], softspan_3[1], softspan_3[0]};
end else if (NUM_CHANNELS == 4) begin
assign softspan_24 = {softspan_3[3], softspan_3[2], softspan_3[1], softspan_3[0], 12'b0};
end else begin
assign softspan_24 = {softspan_3[1], softspan_3[0], 18'b0};
end
endgenerate
// processor read/write interface
always @(negedge up_rstn or posedge up_clk) begin
if (up_rstn == 0) begin
up_wack <= 'd0;
up_rack <= 'd0;
up_rdata <= 'd0;
end else begin
up_wack <= |up_wack_s;
up_rack <= |up_rack_s;
up_rdata <= up_rdata_s[0] |
up_rdata_s[1] |
up_rdata_s[2] |
up_rdata_s[3] |
up_rdata_s[4] |
up_rdata_s[5] |
up_rdata_s[6] |
up_rdata_s[7] |
up_rdata_s[8];
end
end
// CMOS/LVDS INTERFACE
generate
if (EXTERNAL_CLK == 1'b1) begin
assign adc_clk_s = external_clk;
end else begin
assign adc_clk_s = up_clk;
end
if (LVDS_CMOS_N == 1) begin
axi_ltc235x_lvds #(
.XILINX_INTEL_N (XILINX_INTEL_N),
.LTC235X_FAMILY (LTC235X_FAMILY),
.NUM_CHANNELS (NUM_CHANNELS),
.DATA_WIDTH (DATA_WIDTH)
) i_ltc235x_lvds (
.rst (adc_rst_s),
.clk (adc_clk_s),
.adc_enable (adc_enable),
.softspan_next (softspan_24),
.scki_p (scki_p),
.scki_n (scki_n),
.sdi_p (sdi_p),
.sdi_n (sdi_n),
.scko_p (scko_p),
.scko_n (scko_n),
.sdo_p (sdo_p),
.sdo_n (sdo_n),
.busy (busy),
.adc_ch0_id (adc_status_header[0]),
.adc_ch1_id (adc_status_header[1]),
.adc_ch2_id (adc_status_header[2]),
.adc_ch3_id (adc_status_header[3]),
.adc_ch4_id (adc_status_header[4]),
.adc_ch5_id (adc_status_header[5]),
.adc_ch6_id (adc_status_header[6]),
.adc_ch7_id (adc_status_header[7]),
.adc_data_0 (adc_data_0),
.adc_data_1 (adc_data_1),
.adc_data_2 (adc_data_2),
.adc_data_3 (adc_data_3),
.adc_data_4 (adc_data_4),
.adc_data_5 (adc_data_5),
.adc_data_6 (adc_data_6),
.adc_data_7 (adc_data_7),
.adc_softspan_0 (),
.adc_softspan_1 (),
.adc_softspan_2 (),
.adc_softspan_3 (),
.adc_softspan_4 (),
.adc_softspan_5 (),
.adc_softspan_6 (),
.adc_softspan_7 (),
.adc_valid (adc_valid));
end else begin
axi_ltc235x_cmos #(
.LTC235X_FAMILY (LTC235X_FAMILY),
.ACTIVE_LANES (ACTIVE_LANES),
.NUM_CHANNELS (NUM_CHANNELS),
.DATA_WIDTH (DATA_WIDTH)
) i_ltc235x_cmos (
.rst (adc_rst_s),
.clk (adc_clk_s),
.adc_enable (adc_enable),
.softspan_next (softspan_24),
.scki (scki),
.sdi (sdi),
.scko (scko),
.sdo (sdo),
.busy (busy),
.adc_ch0_id (adc_status_header[0]),
.adc_ch1_id (adc_status_header[1]),
.adc_ch2_id (adc_status_header[2]),
.adc_ch3_id (adc_status_header[3]),
.adc_ch4_id (adc_status_header[4]),
.adc_ch5_id (adc_status_header[5]),
.adc_ch6_id (adc_status_header[6]),
.adc_ch7_id (adc_status_header[7]),
.adc_data_0 (adc_data_0),
.adc_data_1 (adc_data_1),
.adc_data_2 (adc_data_2),
.adc_data_3 (adc_data_3),
.adc_data_4 (adc_data_4),
.adc_data_5 (adc_data_5),
.adc_data_6 (adc_data_6),
.adc_data_7 (adc_data_7),
.adc_softspan_0 (),
.adc_softspan_1 (),
.adc_softspan_2 (),
.adc_softspan_3 (),
.adc_softspan_4 (),
.adc_softspan_5 (),
.adc_softspan_6 (),
.adc_softspan_7 (),
.adc_valid (adc_valid));
end
endgenerate
// regmap adc channels
generate
genvar i;
for (i = 0; i < NUM_CHANNELS; i=i+1) begin : regmap_channels
up_adc_channel #(
.CHANNEL_ID(i)
) i_up_adc_channel (
.adc_clk (adc_clk_s),
.adc_rst (adc_rst_s),
.adc_enable (adc_enable[i]),
.adc_iqcor_enb (),
.adc_dcfilt_enb (),
.adc_dfmt_se (),
.adc_dfmt_type (),
.adc_dfmt_enable (),
.adc_dcfilt_offset (),
.adc_dcfilt_coeff (),
.adc_iqcor_coeff_1 (),
.adc_iqcor_coeff_2 (),
.adc_pnseq_sel (),
.adc_data_sel (),
.adc_pn_err (1'b0),
.adc_pn_oos (1'b0),
.adc_or (1'b0),
.adc_read_data (adc_data[i]),
.adc_status_header({5'd0, adc_status_header[i]}),
.adc_crc_err(1'b0),
.adc_softspan (softspan_3[i]),
.up_adc_crc_err (),
.up_adc_pn_err (),
.up_adc_pn_oos (),
.up_adc_or (),
.up_usr_datatype_be (),
.up_usr_datatype_signed (),
.up_usr_datatype_shift (),
.up_usr_datatype_total_bits (),
.up_usr_datatype_bits (),
.up_usr_decimation_m (),
.up_usr_decimation_n (),
.adc_usr_datatype_be (1'b0),
.adc_usr_datatype_signed (1'b1),
.adc_usr_datatype_shift (8'd0),
.adc_usr_datatype_total_bits (8'd32),
.adc_usr_datatype_bits (8'd32),
.adc_usr_decimation_m (16'd1),
.adc_usr_decimation_n (16'd1),
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack_s[i]),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata_s[i]),
.up_rack (up_rack_s[i]));
end
endgenerate
// up adc common
up_adc_common #(
.ID(ID),
.CONFIG(CONFIG)
) i_up_adc_common (
.mmcm_rst (),
.adc_clk (adc_clk_s),
.adc_rst (adc_rst_s),
.adc_r1_mode (),
.adc_ddr_edgesel (),
.adc_pin_mode (),
.adc_status ('h1),
.adc_sync_status (1'b1),
.adc_status_ovf (adc_dovf),
.adc_clk_ratio (32'd1),
.adc_start_code (),
.adc_sref_sync (),
.adc_sync (),
.adc_ext_sync_arm(),
.adc_ext_sync_disarm(),
.adc_ext_sync_manual_req(),
.adc_num_lanes(),
.adc_custom_control(),
.adc_crc_enable(),
.adc_sdr_ddr_n(),
.adc_symb_op(),
.adc_symb_8_16b(),
.up_pps_rcounter (32'b0),
.up_pps_status (1'b0),
.up_pps_irq_mask (),
.up_adc_r1_mode(),
.up_adc_ce (),
.up_status_pn_err (1'b0),
.up_status_pn_oos (1'b0),
.up_status_or (1'b0),
.up_drp_sel (),
.up_drp_wr (),
.up_drp_addr (),
.up_drp_wdata (),
.up_drp_rdata (32'd0),
.up_drp_ready (1'd0),
.up_drp_locked (1'd1),
.adc_config_wr (),
.adc_config_ctrl (),
.adc_config_rd (32'd0),
.adc_ctrl_status (1'd0),
.up_usr_chanmax_out (),
.up_usr_chanmax_in (8),
.up_adc_gpio_in (32'b0),
.up_adc_gpio_out (),
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack_s[8]),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata_s[8]),
.up_rack (up_rack_s[8]));
// up bus interface
up_axi #(
.AXI_ADDRESS_WIDTH (16)
) i_up_axi (
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_axi_awvalid (s_axi_awvalid),
.up_axi_awaddr (s_axi_awaddr),
.up_axi_awready (s_axi_awready),
.up_axi_wvalid (s_axi_wvalid),
.up_axi_wdata (s_axi_wdata),
.up_axi_wstrb (s_axi_wstrb),
.up_axi_wready (s_axi_wready),
.up_axi_bvalid (s_axi_bvalid),
.up_axi_bresp (s_axi_bresp),
.up_axi_bready (s_axi_bready),
.up_axi_arvalid (s_axi_arvalid),
.up_axi_araddr (s_axi_araddr),
.up_axi_arready (s_axi_arready),
.up_axi_rvalid (s_axi_rvalid),
.up_axi_rresp (s_axi_rresp),
.up_axi_rdata (s_axi_rdata),
.up_axi_rready (s_axi_rready),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata),
.up_rack (up_rack));
endmodule
+529
View File
@@ -0,0 +1,529 @@
// ***************************************************************************
// ***************************************************************************
// 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_ltc235x_cmos #(
parameter ACTIVE_LANES = 8'b1111_1111,
parameter LTC235X_FAMILY = 0,
parameter NUM_CHANNELS = 8, // 8 for 2358, 4 for 2357, 2 for 2353
parameter DATA_WIDTH = 18 // 18 or 16 based on -18/-16
) (
input rst,
input clk,
input [ 7:0] adc_enable,
input [23:0] softspan_next,
// physical interface
output scki,
output sdi,
input scko,
input [ 7:0] sdo,
input busy,
// FIFO interface
output [ 2:0] adc_ch0_id,
output [ 2:0] adc_ch1_id,
output [ 2:0] adc_ch2_id,
output [ 2:0] adc_ch3_id,
output [ 2:0] adc_ch4_id,
output [ 2:0] adc_ch5_id,
output [ 2:0] adc_ch6_id,
output [ 2:0] adc_ch7_id,
output [31:0] adc_data_0,
output [31:0] adc_data_1,
output [31:0] adc_data_2,
output [31:0] adc_data_3,
output [31:0] adc_data_4,
output [31:0] adc_data_5,
output [31:0] adc_data_6,
output [31:0] adc_data_7,
output [ 2:0] adc_softspan_0,
output [ 2:0] adc_softspan_1,
output [ 2:0] adc_softspan_2,
output [ 2:0] adc_softspan_3,
output [ 2:0] adc_softspan_4,
output [ 2:0] adc_softspan_5,
output [ 2:0] adc_softspan_6,
output [ 2:0] adc_softspan_7,
output reg adc_valid
);
localparam DW = 24; // packet size
localparam BW = DW - 1;
// internal registers
reg busy_m1;
reg busy_m2;
reg busy_m3;
reg [ 4:0] scki_counter = 5'h0;
reg [ 4:0] data_counter = 5'h0;
reg scki_i;
reg scki_d;
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 [BW:0] adc_data_init[7:0];
reg [BW:0] adc_data_store[7:0];
reg [ 2:0] lane_0_ch = 3'd0;
reg [ 2:0] lane_1_ch = 3'd0;
reg [ 2:0] lane_2_ch = 3'd0;
reg [ 2:0] lane_3_ch = 3'd0;
reg [ 2:0] lane_4_ch = 3'd0;
reg [ 2:0] lane_5_ch = 3'd0;
reg [ 2:0] lane_6_ch = 3'd0;
reg [ 2:0] lane_7_ch = 3'd0;
reg [ 3:0] adc_lane0_shift;
reg [ 3:0] adc_lane1_shift;
reg [ 3:0] adc_lane2_shift;
reg [ 3:0] adc_lane3_shift;
reg [ 3:0] adc_lane4_shift;
reg [ 3:0] adc_lane5_shift;
reg [ 3:0] adc_lane6_shift;
reg [ 3:0] adc_lane7_shift;
reg [ 3:0] adc_lane0_shift_d;
reg [ 3:0] adc_lane1_shift_d;
reg [ 3:0] adc_lane2_shift_d;
reg [ 3:0] adc_lane3_shift_d;
reg [ 3:0] adc_lane4_shift_d;
reg [ 3:0] adc_lane5_shift_d;
reg [ 3:0] adc_lane6_shift_d;
reg [ 3:0] adc_lane7_shift_d;
reg adc_valid_init;
reg adc_valid_init_d;
reg [ 7:0] ch_data_lock = 8'hff;
reg [ 7:0] ch_capture;
reg [ 7:0] ch_captured;
reg scko_d;
reg [ 7:0] sdo_d;
reg [ 4:0] sdi_index = 5'd23;
reg [23:0] softspan_next_int;
// internal wires
wire start_transfer_s;
wire scki_cnt_rst;
wire acquire_data;
wire [17:0] adc_data_raw_s [7:0];
wire [31:0] adc_data_sign_s [7:0];
wire [31:0] adc_data_zero_s [7:0];
wire [31:0] adc_data_s [7:0];
wire [ 2:0] adc_ch_id_s [7:0];
wire [ 2:0] adc_softspan_s [7:0];
always @(posedge clk) begin
if (rst == 1'b1) begin
busy_m1 <= 1'b0;
busy_m2 <= 1'b0;
end else begin
busy_m1 <= busy;
busy_m2 <= busy_m1;
busy_m3 <= busy_m2;
end
end
assign start_transfer_s = busy_m3 & ~busy_m2;
// reading clock logic
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 (acquire_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 + 5'd1;
scki_i <= 1'b1;
end else begin
scki_counter <= scki_counter;
scki_i <= ~scki_i;
end
end
end
assign scki_cnt_rst = (scki_counter == DW);
assign scki = scki_i | ~acquire_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 requested if the reading process is 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.
The ring buffer contains the crc data on the 8(last position.)
e.g for a 4'th reading cycle:
line 0 = ch 3
line 1 = ch 4
line 2 = ch 5
line 3 = ch 6
line 4 = ch 7
line 5 = crc
line 6 = ch 0
line 7 = ch 1
Because there is no rule for a specific number of lanes to be enabled at a given time
the interface can handle every combination of enabled lanes with enabled channels.
The valid signal will only be asserted after all enabled channels are stored.
This means that the user must adjust the sampling frequency based on the
interface clock frequency and the maximum position/index
difference +1 of a channel data and the first enabled lane that will
pass that channels data, maximum difference is 8(e.g line 0 to line 7).
e.g. If only lanes 1 and 2(0 to 7) are enabled,
1. The user wants to capture the 6'th(0 to 7) channel, 5 reading cycles are required.
2. The user wants to capture channel 0, 8 reading cycles are required.
*/
// capture data per lane in rx buffers adc_lane_X on every edge of scko
// ignore when busy forced scko to 0
always @(posedge clk) begin
scko_d <= scko;
sdo_d <= sdo;
if (scko != scko_d && scki != scki_d) begin
adc_lane_0 <= {adc_lane_0[BW-1:0], sdo_d[0]};
adc_lane_1 <= {adc_lane_1[BW-1:0], sdo_d[1]};
adc_lane_2 <= {adc_lane_2[BW-1:0], sdo_d[2]};
adc_lane_3 <= {adc_lane_3[BW-1:0], sdo_d[3]};
adc_lane_4 <= {adc_lane_4[BW-1:0], sdo_d[4]};
adc_lane_5 <= {adc_lane_5[BW-1:0], sdo_d[5]};
adc_lane_6 <= {adc_lane_6[BW-1:0], sdo_d[6]};
adc_lane_7 <= {adc_lane_7[BW-1:0], sdo_d[7]};
end
end
// store the data from the rx buffers when all bits are received
// when data transaction window is done
// index is based by lane
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 <= 5'h0;
end else begin
data_counter <= scki_counter;
if (data_counter == DW) 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
end
end
// lane_x_ch - channel corresponds to which lane, e.g. lane_0_ch stores the current channel lane 0 has
// ch_data_lock[i] - locks ch i, e.g. ch_data_lock[7] = 1 means data from channel 7 has already been sent to an active lane, channel 7 should now be locked
// dont acquire data if all channels are all already locked
always @(posedge clk) begin
if (start_transfer_s) begin
lane_0_ch <= 3'd0;
lane_1_ch <= 3'd1;
lane_2_ch <= 3'd2;
lane_3_ch <= 3'd3;
lane_4_ch <= 3'd4;
lane_5_ch <= 3'd5;
lane_6_ch <= 3'd6;
lane_7_ch <= 3'd7;
ch_data_lock <= 8'd0;
end else if (acquire_data == 1'b1 && (scki_cnt_rst & (~scki_d & scki_i))) begin
lane_0_ch <= lane_0_ch + 3'd1;
lane_1_ch <= lane_1_ch + 3'd1;
lane_2_ch <= lane_2_ch + 3'd1;
lane_3_ch <= lane_3_ch + 3'd1;
lane_4_ch <= lane_4_ch + 3'd1;
lane_5_ch <= lane_5_ch + 3'd1;
lane_6_ch <= lane_6_ch + 3'd1;
lane_7_ch <= lane_7_ch + 3'd1;
ch_data_lock[lane_0_ch] <= ACTIVE_LANES[0] ? 1'b1 : ch_data_lock[lane_0_ch];
ch_data_lock[lane_1_ch] <= ACTIVE_LANES[1] ? 1'b1 : ch_data_lock[lane_1_ch];
ch_data_lock[lane_2_ch] <= ACTIVE_LANES[2] ? 1'b1 : ch_data_lock[lane_2_ch];
ch_data_lock[lane_3_ch] <= ACTIVE_LANES[3] ? 1'b1 : ch_data_lock[lane_3_ch];
ch_data_lock[lane_4_ch] <= ACTIVE_LANES[4] ? 1'b1 : ch_data_lock[lane_4_ch];
ch_data_lock[lane_5_ch] <= ACTIVE_LANES[5] ? 1'b1 : ch_data_lock[lane_5_ch];
ch_data_lock[lane_6_ch] <= ACTIVE_LANES[6] ? 1'b1 : ch_data_lock[lane_6_ch];
ch_data_lock[lane_7_ch] <= ACTIVE_LANES[7] ? 1'b1 : ch_data_lock[lane_7_ch];
end
end
assign acquire_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]));
// hold lane status and lane channel
// for datasyncing with valid signal
always @(posedge clk) begin
if (rst == 1'b1 || adc_valid == 1'b1) begin
adc_lane0_shift <= 4'd0;
adc_lane1_shift <= 4'd0;
adc_lane2_shift <= 4'd0;
adc_lane3_shift <= 4'd0;
adc_lane4_shift <= 4'd0;
adc_lane5_shift <= 4'd0;
adc_lane6_shift <= 4'd0;
adc_lane7_shift <= 4'd0;
adc_lane0_shift_d <= 4'd0;
adc_lane1_shift_d <= 4'd0;
adc_lane2_shift_d <= 4'd0;
adc_lane3_shift_d <= 4'd0;
adc_lane4_shift_d <= 4'd0;
adc_lane5_shift_d <= 4'd0;
adc_lane6_shift_d <= 4'd0;
adc_lane7_shift_d <= 4'd0;
end else begin
adc_lane0_shift <= {ACTIVE_LANES[0], lane_0_ch};
adc_lane1_shift <= {ACTIVE_LANES[1], lane_1_ch};
adc_lane2_shift <= {ACTIVE_LANES[2], lane_2_ch};
adc_lane3_shift <= {ACTIVE_LANES[3], lane_3_ch};
adc_lane4_shift <= {ACTIVE_LANES[4], lane_4_ch};
adc_lane5_shift <= {ACTIVE_LANES[5], lane_5_ch};
adc_lane6_shift <= {ACTIVE_LANES[6], lane_6_ch};
adc_lane7_shift <= {ACTIVE_LANES[7], lane_7_ch};
adc_lane0_shift_d <= adc_lane0_shift;
adc_lane1_shift_d <= adc_lane1_shift;
adc_lane2_shift_d <= adc_lane2_shift;
adc_lane3_shift_d <= adc_lane3_shift;
adc_lane4_shift_d <= adc_lane4_shift;
adc_lane5_shift_d <= adc_lane5_shift;
adc_lane6_shift_d <= adc_lane6_shift;
adc_lane7_shift_d <= adc_lane7_shift;
end
end
// stores the data from the rx buffer, but now based on ch
// index is based on ch, not lane anymore
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;
end else begin
if (!adc_valid_init_d & adc_valid_init) begin
if (adc_lane0_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane0_shift_d[2:0]] <= adc_data_init[0];
end
if (adc_lane1_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane1_shift_d[2:0]] <= adc_data_init[1];
end
if (adc_lane2_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane2_shift_d[2:0]] <= adc_data_init[2];
end
if (adc_lane3_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane3_shift_d[2:0]] <= adc_data_init[3];
end
if (adc_lane4_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane4_shift_d[2:0]] <= adc_data_init[4];
end
if (adc_lane5_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane5_shift_d[2:0]] <= adc_data_init[5];
end
if (adc_lane6_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane6_shift_d[2:0]] <= adc_data_init[6];
end
if (adc_lane7_shift_d[3] == 1'b1) begin
adc_data_store[adc_lane7_shift_d[2:0]] <= adc_data_init[7];
end
end
end
end
// extract info from the data bits
genvar i;
generate
for (i=0; i < 8; i=i+1) begin: format
assign adc_data_raw_s[i] = adc_data_store[i][BW:DW-DATA_WIDTH];
assign adc_data_sign_s[i] = {{(32-DATA_WIDTH){adc_data_raw_s[i][DATA_WIDTH-1]}}, adc_data_raw_s[i]};
assign adc_data_zero_s[i] = {{(32-DATA_WIDTH){1'b0}}, adc_data_raw_s[i]};
assign adc_data_s[i] = (adc_softspan_s[i] == 3'b0)? 32'h0 :
(adc_softspan_s[i][1])? adc_data_sign_s[i] :
adc_data_zero_s[i] ;
if (NUM_CHANNELS == 8) begin
assign adc_ch_id_s[i] = adc_data_store[i][5:3];
end else if (NUM_CHANNELS == 4) begin
assign adc_ch_id_s[i] = {1'b0, adc_data_store[i][4:3]};
end else begin
assign adc_ch_id_s[i] = {2'b0, adc_data_store[i][3]};
end
assign adc_softspan_s[i] = adc_data_store[i][2:0];
end
endgenerate
// assign extracted adc data to corresponding outputs
assign adc_data_0 = adc_data_s[0];
assign adc_data_1 = adc_data_s[1];
assign adc_data_2 = adc_data_s[2];
assign adc_data_3 = adc_data_s[3];
assign adc_data_4 = adc_data_s[4];
assign adc_data_5 = adc_data_s[5];
assign adc_data_6 = adc_data_s[6];
assign adc_data_7 = adc_data_s[7];
// assign extracted adc channel id to corresponding outputs
assign adc_ch0_id = adc_ch_id_s[0];
assign adc_ch1_id = adc_ch_id_s[1];
assign adc_ch2_id = adc_ch_id_s[2];
assign adc_ch3_id = adc_ch_id_s[3];
assign adc_ch4_id = adc_ch_id_s[4];
assign adc_ch5_id = adc_ch_id_s[5];
assign adc_ch6_id = adc_ch_id_s[6];
assign adc_ch7_id = adc_ch_id_s[7];
// assign extracted adc channel id to corresponding outputs
assign adc_softspan_0 = adc_softspan_s[0];
assign adc_softspan_1 = adc_softspan_s[1];
assign adc_softspan_2 = adc_softspan_s[2];
assign adc_softspan_3 = adc_softspan_s[3];
assign adc_softspan_4 = adc_softspan_s[4];
assign adc_softspan_5 = adc_softspan_s[5];
assign adc_softspan_6 = adc_softspan_s[6];
assign adc_softspan_7 = adc_softspan_s[7];
// initial valid signal
always @(posedge clk) begin
if (rst == 1'b1) begin
adc_valid_init <= 1'b0;
end else begin
if (data_counter == DW && adc_valid_init == 1'b0) begin
adc_valid_init <= 1'b1;
end else begin
adc_valid_init <= 1'b0;
end
end
end
// delayed both valid signal and data_lock signal
// for datasyncing with valid signal
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 <= 8'd0;
ch_captured <= 8'd0;
end else begin
ch_capture <= ch_data_lock;
ch_captured <= ch_capture;
adc_valid_init_d <= adc_valid_init;
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]);
end
end
// every negedge of scki, update index of sdi
always @(posedge clk) begin
if (start_transfer_s || rst) begin
sdi_index <= 5'd23;
end else begin
if (scki && !scki_d && sdi_index != 5'b11111) begin
sdi_index <= sdi_index - 5'b1;
end
end
end
// update next softspan configuration every after busy
always @(posedge clk) begin
if (rst == 1'b1) begin
softspan_next_int <= 24'hff_ffff;
end else begin
if (busy_m3 & ~busy_m2) begin
softspan_next_int <= softspan_next;
end else begin
softspan_next_int <= softspan_next_int;
end
end
end
assign sdi = (sdi_index != 5'b11111)? softspan_next_int[sdi_index] : 1'b0;
endmodule
@@ -0,0 +1,97 @@
###############################################################################
## Copyright (C) 2023 Analog Devices, Inc. All rights reserved.
### SPDX short identifier: ADIBSD
###############################################################################
# ip
package require qsys 14.0
package require quartus::device
source ../../scripts/adi_env.tcl
source ../scripts/adi_ip_intel.tcl
ad_ip_create axi_ltc235x {AXI LTC235x Interface} axi_ltc235x_elab
set_module_property AUTHOR {Geronimo, John Erasmus Mari F.}
set_module_property VALIDATION_CALLBACK info_param_validate
ad_ip_files axi_ltc235x [list \
$ad_hdl_dir/library/common/up_axi.v \
$ad_hdl_dir/library/common/up_adc_common.v \
$ad_hdl_dir/library/common/ad_rst.v \
$ad_hdl_dir/library/common/up_xfer_cntrl.v \
$ad_hdl_dir/library/common/up_xfer_status.v \
$ad_hdl_dir/library/common/up_clock_mon.v \
$ad_hdl_dir/library/common/up_adc_channel.v \
$ad_hdl_dir/library/intel/common/up_xfer_cntrl_constr.sdc \
$ad_hdl_dir/library/intel/common/up_rst_constr.sdc \
$ad_hdl_dir/library/intel/common/up_xfer_status_constr.sdc \
$ad_hdl_dir/library/intel/common/up_clock_mon_constr.sdc \
axi_ltc235x_cmos.v \
axi_ltc235x_lvds.v \
axi_ltc235x.v]
add_documentation_link "AXI_LTC235x IP core" https://wiki.analog.com/resources/fpga/docs/axi_ltc235x
ad_ip_parameter ID INTEGER 0
ad_ip_parameter XILINX_INTEL_N INTEGER 0
ad_ip_parameter LVDS_CMOS_N INTEGER 0
ad_ip_parameter LANE_0_ENABLE INTEGER 1
ad_ip_parameter LANE_1_ENABLE INTEGER 1
ad_ip_parameter LANE_2_ENABLE INTEGER 1
ad_ip_parameter LANE_3_ENABLE INTEGER 1
ad_ip_parameter LANE_4_ENABLE INTEGER 1
ad_ip_parameter LANE_5_ENABLE INTEGER 1
ad_ip_parameter LANE_6_ENABLE INTEGER 1
ad_ip_parameter LANE_7_ENABLE INTEGER 1
ad_ip_parameter EXTERNAL_CLK INTEGER 0
ad_ip_parameter LTC235X_FAMILY INTEGER 0
ad_ip_parameter NUM_CHANNELS INTEGER 8
ad_ip_parameter DATA_WIDTH INTEGER 18
adi_add_auto_fpga_spec_params
proc axi_ltc235x_elab {} {
# interfaces
# physical interface
add_interface device_if conduit end
# common
add_interface_port device_if busy busy Input 1
add_interface_port device_if lvds_cmos_n lvds_cmos_n Output 1
set interface [get_parameter_value LVDS_CMOS_N]
switch $interface {
"0" { ;# cmos
add_interface_port device_if scki scki Output 1
add_interface_port device_if scko scko Input 1
add_interface_port device_if sdi sdi Output 1
add_interface_port device_if sdo sdo Input 8}
"1" { ;# lvds
add_interface_port device_if scki_p scki_p Output 1
add_interface_port device_if scki_n scki_n Output 1
add_interface_port device_if scko_p scko_p Input 1
add_interface_port device_if scko_n scko_n Input 1
add_interface_port device_if sdi_p sdi_p Output 1
add_interface_port device_if sdi_n sdi_n Output 1
add_interface_port device_if sdo_p sdo_p Input 1
add_interface_port device_if sdo_n sdo_n Input 1}
}
# clock
ad_interface clock external_clk input 1
# axi
ad_ip_intf_s_axi s_axi_aclk s_axi_aresetn
# others
ad_interface signal adc_dovf Input 1 ovf
set num_channels [get_parameter_value NUM_CHANNELS]
for {set i 0} {$i < $num_channels} {incr i} {
add_interface adc_ch_$i conduit end
add_interface_port adc_ch_$i adc_enable_$i enable Output 1
add_interface_port adc_ch_$i adc_valid_$i valid Output 1
add_interface_port adc_ch_$i adc_data_$i data Output 32
set_interface_property adc_ch_$i associatedClock if_external_clk
set_interface_property adc_ch_$i associatedReset ""
}
}
+407
View File
@@ -0,0 +1,407 @@
// ***************************************************************************
// ***************************************************************************
// 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_ltc235x_lvds #(
parameter XILINX_INTEL_N = 0,
parameter LTC235X_FAMILY = 0,
parameter NUM_CHANNELS = 8, // 8 for 2358, 4 for 2357, 2 for 2353
parameter DATA_WIDTH = 18 // 18 or 16 based on -18/-16
) (
input rst,
input clk,
input [ 7:0] adc_enable,
input [23:0] softspan_next,
// physical interface
output scki_p,
output scki_n,
output sdi_p,
output sdi_n,
input scko_p,
input scko_n,
input sdo_p,
input sdo_n,
input busy,
// FIFO interface
output [ 2:0] adc_ch0_id,
output [ 2:0] adc_ch1_id,
output [ 2:0] adc_ch2_id,
output [ 2:0] adc_ch3_id,
output [ 2:0] adc_ch4_id,
output [ 2:0] adc_ch5_id,
output [ 2:0] adc_ch6_id,
output [ 2:0] adc_ch7_id,
output [31:0] adc_data_0,
output [31:0] adc_data_1,
output [31:0] adc_data_2,
output [31:0] adc_data_3,
output [31:0] adc_data_4,
output [31:0] adc_data_5,
output [31:0] adc_data_6,
output [31:0] adc_data_7,
output [ 2:0] adc_softspan_0,
output [ 2:0] adc_softspan_1,
output [ 2:0] adc_softspan_2,
output [ 2:0] adc_softspan_3,
output [ 2:0] adc_softspan_4,
output [ 2:0] adc_softspan_5,
output [ 2:0] adc_softspan_6,
output [ 2:0] adc_softspan_7,
output reg adc_valid
);
// local parameters
localparam DW = 24; // packet size per channel
localparam DW_8 = 24 * 8; // packet size for all 8 channels
localparam BW = DW - 1;
localparam BW_8 = DW_8 - 1;
// internal registers
reg busy_m1;
reg busy_m2;
reg busy_m3;
reg [ 8:0] scki_counter = 9'h0;
reg [ 8:0] data_counter = 9'h0;
reg scki_i;
reg scki_d;
reg [BW_8:0] adc_lane;
reg [BW_8:0] adc_data_init;
reg [ BW:0] adc_data_store[7:0];
reg adc_valid_init;
reg adc_valid_init_d;
reg ch_data_lock = 1;
reg ch_capture;
reg ch_captured;
reg scko_d;
reg sdo_d;
reg [ 4:0] sdi_index = 5'd23;
reg [23:0] softspan_next_int;
// internal wires
wire start_transfer_s;
wire scki_cnt_rst;
wire acquire_data;
wire [DATA_WIDTH-1:0] adc_data_raw_s [7:0];
wire [31:0] adc_data_sign_s [7:0];
wire [31:0] adc_data_zero_s [7:0];
wire [31:0] adc_data_s [7:0];
wire [ 2:0] adc_ch_id_s [7:0];
wire [ 2:0] adc_softspan_s [7:0];
wire scki_s;
wire sdi_s;
wire scko_s;
wire sdo_s;
generate
if (XILINX_INTEL_N == 0) begin
assign scki_p = scki_s;
assign scki_n = 1'b0;
assign sdi_p = sdi_s;
assign sdi_n = 1'b0;
assign scko_s = scko_p;
assign sdo_s = sdo_p;
end else begin
OBUFDS obufds_scki (
.O(scki_n),
.OB(scki_p),
.I(scki_s));
OBUFDS obufds_sdi (
.O(sdi_n),
.OB(sdi_p),
.I(sdi_s));
IBUFDS #(
.CCIO_EN_M("TRUE"),
.CCIO_EN_S("TRUE")
) ibufds_scko (
.O(scko_s),
.I(scko_p),
.IB(scko_n));
IBUFDS #(
.CCIO_EN_M("TRUE"),
.CCIO_EN_S("TRUE")
) ibufds_sdo (
.O(sdo_s),
.I(sdo_p),
.IB(sdo_n));
end
endgenerate
always @(posedge clk) begin
if (rst == 1'b1) begin
busy_m1 <= 1'b0;
busy_m2 <= 1'b0;
end else begin
busy_m1 <= busy;
busy_m2 <= busy_m1;
busy_m3 <= busy_m2;
end
end
assign start_transfer_s = busy_m3 & ~busy_m2;
// reading clock logic
always @(posedge clk) begin
if (rst) begin
scki_counter <= 9'h0;
scki_i <= 1'b0;
scki_d <= 1'b0;
end else begin
scki_d <= scki_i;
if (acquire_data == 1'b0) begin
scki_counter <= 9'h0;
scki_i <= 1'b0;
end else if (scki_cnt_rst & (scki_d != scki_i)) begin // end of a capture
scki_counter <= 9'h1;
scki_i <= 1'b0;
end else begin
scki_counter <= scki_counter + 9'd1;
scki_i <= ~scki_i;
end
end
end
assign scki_cnt_rst = (scki_counter == DW_8);
assign scki_s = scki_i & acquire_data;
// capture data per lane in rx buffer on every edge of scko_s
// ignore when busy forced scko_s to 0
always @(posedge clk) begin
scko_d <= scko_s;
sdo_d <= sdo_s;
if (scko_s != scko_d && scki_s != scki_d) begin
adc_lane <= {adc_lane[BW_8-1:0], sdo_d};
end
end
// store the data from the rx buffers when all bits are received
// when data transaction window is done
always @(posedge clk) begin
if (rst == 1'b1) begin
adc_data_init <= 'h0;
data_counter <= 9'h0;
end else begin
data_counter <= scki_counter;
if (data_counter == DW_8) begin
adc_data_init <= adc_lane;
end
end
end
// ch_data_lock - locks all the channel, means dont acquire data if all ch's are lock while acquire_data = 0
always @(posedge clk) begin
if (start_transfer_s) begin
ch_data_lock <= 1'd0;
end else if (acquire_data == 1'b1 && (scki_cnt_rst & (scki_d != scki_i))) begin
ch_data_lock <= 1'd1;
end
end
assign acquire_data = ~((ch_data_lock | ~adc_enable[0]) &
(ch_data_lock | ~adc_enable[1]) &
(ch_data_lock | ~adc_enable[2]) &
(ch_data_lock | ~adc_enable[3]) &
(ch_data_lock | ~adc_enable[4]) &
(ch_data_lock | ~adc_enable[5]) &
(ch_data_lock | ~adc_enable[6]) &
(ch_data_lock | ~adc_enable[7]));
// stores the data from the rx buffer, but now based on ch
// from the whole buffer into the per channel buffer
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;
end else begin
if (!adc_valid_init_d & adc_valid_init) begin
adc_data_store[0] <= adc_data_init[BW + DW * 7: DW * 7];
adc_data_store[1] <= adc_data_init[BW + DW * 6: DW * 6];
adc_data_store[2] <= adc_data_init[BW + DW * 5: DW * 5];
adc_data_store[3] <= adc_data_init[BW + DW * 4: DW * 4];
adc_data_store[4] <= adc_data_init[BW + DW * 3: DW * 3];
adc_data_store[5] <= adc_data_init[BW + DW * 2: DW * 2];
adc_data_store[6] <= adc_data_init[BW + DW * 1: DW * 1];
adc_data_store[7] <= adc_data_init[BW + DW * 0: DW * 0];
end
end
end
// extract info from the data bits
genvar i;
generate
for (i=0; i < 8; i=i+1) begin: format
assign adc_data_raw_s[i] = adc_data_store[i][BW:DW-DATA_WIDTH];
assign adc_data_sign_s[i] = {{(32-DATA_WIDTH){adc_data_raw_s[i][DATA_WIDTH-1]}}, adc_data_raw_s[i]};
assign adc_data_zero_s[i] = {{(32-DATA_WIDTH){1'b0}}, adc_data_raw_s[i]};
assign adc_data_s[i] = (adc_softspan_s[i] == 3'b0)? 32'h0 :
(adc_softspan_s[i][1])? adc_data_sign_s[i] :
adc_data_zero_s[i] ;
if (NUM_CHANNELS == 8) begin
assign adc_ch_id_s[i] = adc_data_store[i][5:3];
end else if (NUM_CHANNELS == 4) begin
assign adc_ch_id_s[i] = {1'b0, adc_data_store[i][4:3]};
end else begin
assign adc_ch_id_s[i] = {2'b0, adc_data_store[i][3]};
end
assign adc_softspan_s[i] = adc_data_store[i][2:0];
end
endgenerate
// assign extracted adc data to corresponding outputs
assign adc_data_0 = adc_data_s[0];
assign adc_data_1 = adc_data_s[1];
assign adc_data_2 = adc_data_s[2];
assign adc_data_3 = adc_data_s[3];
assign adc_data_4 = adc_data_s[4];
assign adc_data_5 = adc_data_s[5];
assign adc_data_6 = adc_data_s[6];
assign adc_data_7 = adc_data_s[7];
// assign extracted adc channel id to corresponding outputs
assign adc_ch0_id = adc_ch_id_s[0];
assign adc_ch1_id = adc_ch_id_s[1];
assign adc_ch2_id = adc_ch_id_s[2];
assign adc_ch3_id = adc_ch_id_s[3];
assign adc_ch4_id = adc_ch_id_s[4];
assign adc_ch5_id = adc_ch_id_s[5];
assign adc_ch6_id = adc_ch_id_s[6];
assign adc_ch7_id = adc_ch_id_s[7];
// assign extracted adc channel id to corresponding outputs
assign adc_softspan_0 = adc_softspan_s[0];
assign adc_softspan_1 = adc_softspan_s[1];
assign adc_softspan_2 = adc_softspan_s[2];
assign adc_softspan_3 = adc_softspan_s[3];
assign adc_softspan_4 = adc_softspan_s[4];
assign adc_softspan_5 = adc_softspan_s[5];
assign adc_softspan_6 = adc_softspan_s[6];
assign adc_softspan_7 = adc_softspan_s[7];
// initial valid signal
always @(posedge clk) begin
if (rst == 1'b1) begin
adc_valid_init <= 1'b0;
end else begin
if (data_counter == DW_8 && adc_valid_init == 1'b0) begin
adc_valid_init <= 1'b1;
end else begin
adc_valid_init <= 1'b0;
end
end
end
// delayed both valid signal and data_lock signal
// for datasyncing with valid signal
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 <= 1'd0;
ch_captured <= 1'd0;
end else begin
ch_capture <= ch_data_lock;
ch_captured <= ch_capture;
adc_valid_init_d <= adc_valid_init;
adc_valid <= adc_valid_init_d &
(ch_captured | ~adc_enable[0]) &
(ch_captured | ~adc_enable[1]) &
(ch_captured | ~adc_enable[2]) &
(ch_captured | ~adc_enable[3]) &
(ch_captured | ~adc_enable[4]) &
(ch_captured | ~adc_enable[5]) &
(ch_captured | ~adc_enable[6]) &
(ch_captured | ~adc_enable[7]);
end
end
// every negedge of clk, update index of sdi_s
always @(negedge clk) begin
if (start_transfer_s || rst) begin
sdi_index <= 5'd23;
end else begin
if (scki_s != scki_d && sdi_index != 5'b11111) begin
sdi_index <= sdi_index - 5'b1;
end
end
end
// update next softspan configuration every after busy
always @(posedge clk) begin
if (rst == 1'b1) begin
softspan_next_int <= 24'hff_ffff;
end else begin
if (busy_m3 & ~busy_m2) begin
softspan_next_int <= softspan_next;
end else begin
softspan_next_int <= softspan_next_int;
end
end
end
assign sdi_s = (sdi_index != 5'b11111)? softspan_next_int[sdi_index] : 1'b0;
endmodule