library/axi_ad3552r: Added interface IP for Xilinx projects.

The custom interface IP for AD3552R DAC has more operation capabilities:
  - 8b register read/write SDR/DDR
  - 16b register read/write SDR/DDR
  - data stream SDR/DDR ( clk_in/8 or clk_in/4 update rate)
  - selectable input source : DMA/ADC/TEST_RAMP
  - data out clock(SCLK) has clk_in/8 frequency when the converter is configured and clk_in/2 when the converter is in stream mode
  - the IP reference clock (clk_in) can have a maximum frequency of 132MHz
  - the IP has multiple device synchronization capability when the DMA is set as an input data source

Signed-off-by: PopPaul2021 <Paul.Pop@analog.com>
main
PopPaul2021 2023-09-07 09:14:35 +03:00 committed by PopPaul2021
parent 86836f5a40
commit cd33c99b94
9 changed files with 1371 additions and 0 deletions

View File

@ -14,6 +14,7 @@ all: lib
clean:
$(MAKE) -C ad463x_data_capture clean
$(MAKE) -C axi_ad3552r clean
$(MAKE) -C axi_ad5766 clean
$(MAKE) -C axi_ad7606x clean
$(MAKE) -C axi_ad7616 clean
@ -137,6 +138,7 @@ clean-all:clean
lib:
$(MAKE) -C ad463x_data_capture
$(MAKE) -C axi_ad3552r
$(MAKE) -C axi_ad5766
$(MAKE) -C axi_ad7606x
$(MAKE) -C axi_ad7616

35
library/axi_ad3552r/Makefile Executable file
View File

@ -0,0 +1,35 @@
####################################################################################
## Copyright (c) 2018 - 2023 Analog Devices, Inc.
### SPDX short identifier: BSD-1-Clause
## Auto-generated, do not modify!
####################################################################################
LIBRARY_NAME := axi_ad3552r
GENERIC_DEPS += ../common/ad_addsub.v
GENERIC_DEPS += ../common/ad_dds.v
GENERIC_DEPS += ../common/ad_dds_1.v
GENERIC_DEPS += ../common/ad_dds_2.v
GENERIC_DEPS += ../common/ad_dds_cordic_pipe.v
GENERIC_DEPS += ../common/ad_dds_sine.v
GENERIC_DEPS += ../common/ad_dds_sine_cordic.v
GENERIC_DEPS += ../common/ad_rst.v
GENERIC_DEPS += ../common/up_axi.v
GENERIC_DEPS += ../common/up_clock_mon.v
GENERIC_DEPS += ../common/up_dac_channel.v
GENERIC_DEPS += ../common/up_dac_common.v
GENERIC_DEPS += ../common/up_xfer_cntrl.v
GENERIC_DEPS += ../common/up_xfer_status.v
GENERIC_DEPS += axi_ad3552r.v
GENERIC_DEPS += axi_ad3552r_channel.v
GENERIC_DEPS += axi_ad3552r_core.v
GENERIC_DEPS += axi_ad3552r_if.v
XILINX_DEPS += ../xilinx/common/ad_mul.v
XILINX_DEPS += ../xilinx/common/ad_rst_constr.xdc
XILINX_DEPS += ../xilinx/common/up_clock_mon_constr.xdc
XILINX_DEPS += ../xilinx/common/up_xfer_cntrl_constr.xdc
XILINX_DEPS += ../xilinx/common/up_xfer_status_constr.xdc
XILINX_DEPS += axi_ad3552r_ip.tcl
include ../scripts/library.mk

233
library/axi_ad3552r/axi_ad3552r.v Executable file
View File

@ -0,0 +1,233 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2022-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_ad3552r #(
parameter ID = 0,
parameter FPGA_TECHNOLOGY = 0,
parameter FPGA_FAMILY = 0,
parameter SPEED_GRADE = 0,
parameter DEV_PACKAGE = 0,
parameter DDS_DISABLE = 0,
parameter DDS_TYPE = 1,
parameter DDS_CORDIC_DW = 16,
parameter DDS_CORDIC_PHASE_DW = 16
) (
// DAC INTERFACE
input dac_clk,
input [31:0] dma_data,
input valid_in_dma,
input valid_in_dma_sec,
output dac_data_ready,
input [15:0] data_in_a,
input [15:0] data_in_b,
input valid_in_a,
input valid_in_b,
output dac_sclk,
output dac_csn,
input [ 3:0] sdio_i,
output [ 3:0] sdio_o,
output sdio_t,
// sync transfer between 2 DAC'S
input external_sync,
output sync_ext_device,
// axi interface
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
);
// internal clocks and resets
wire dac_rst_s;
wire up_clk;
wire up_rstn;
// internal signals
wire up_wreq_s;
wire [13:0] up_waddr_s;
wire [31:0] up_wdata_s;
wire up_wack_s;
wire up_rreq_s;
wire [13:0] up_raddr_s;
wire [31:0] up_rdata_s;
wire up_rack_s;
wire [ 7:0] address;
wire [23:0] data_read;
wire [23:0] data_write;
wire ddr_sdr_n;
wire symb_8_16b;
wire transfer_data;
wire stream;
wire [31:0] dac_data;
wire dac_valid;
wire if_busy;
wire dac_ext_sync_arm;
// signal name changes
assign up_clk = s_axi_aclk;
assign up_rstn = s_axi_aresetn;
// device interface
axi_ad3552r_if axi_ad3552r_interface (
.clk_in(dac_clk),
.reset_in(dac_rst_s),
.dac_data(dac_data),
.dac_data_valid(dac_valid),
.dac_data_valid_ext(valid_in_dma_sec),
.dac_data_ready(dac_data_ready),
.address(address),
.data_read(data_read),
.data_write(data_write),
.sdr_ddr_n(sdr_ddr_n),
.symb_8_16b(symb_8_16b),
.transfer_data(transfer_data),
.stream(stream),
.if_busy(if_busy),
.external_sync(external_sync),
.external_sync_arm(dac_ext_sync_arm),
.sync_ext_device(sync_ext_device),
.sclk(dac_sclk),
.csn(dac_csn),
.sdio_i(sdio_i),
.sdio_o(sdio_o),
.sdio_t(sdio_t));
// core
axi_ad3552r_core #(
.ID(ID),
.FPGA_TECHNOLOGY(FPGA_TECHNOLOGY),
.FPGA_FAMILY(FPGA_FAMILY),
.SPEED_GRADE(SPEED_GRADE),
.DEV_PACKAGE(DEV_PACKAGE),
.DDS_DISABLE(DDS_DISABLE),
.DDS_TYPE(DDS_TYPE),
.DDS_CORDIC_DW(DDS_CORDIC_DW),
.DDS_CORDIC_PHASE_DW(DDS_CORDIC_PHASE_DW)
) axi_ad3552r_up_core (
.dac_clk(dac_clk),
.dac_rst(dac_rst_s),
.adc_data_in_a(data_in_a),
.adc_data_in_b(data_in_b),
.dma_data(dma_data),
.adc_valid_in_a(valid_in_a),
.adc_valid_in_b(valid_in_b),
.valid_in_dma(valid_in_dma),
.dac_data_ready(dac_data_ready),
.dac_data(dac_data),
.dac_valid(dac_valid),
.address(address),
.data_read(data_read),
.data_write(data_write),
.sdr_ddr_n(sdr_ddr_n),
.symb_8_16b(symb_8_16b),
.transfer_data(transfer_data),
.stream(stream),
.dac_ext_sync_arm(dac_ext_sync_arm),
.if_busy(if_busy),
.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),
.up_rreq(up_rreq_s),
.up_raddr(up_raddr_s),
.up_rdata(up_rdata_s),
.up_rack(up_rack_s));
// up bus interface
up_axi 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_s),
.up_rreq(up_rreq_s),
.up_raddr(up_raddr_s),
.up_rdata(up_rdata_s),
.up_rack(up_rack_s));
endmodule

View File

@ -0,0 +1,227 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2022-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 modificat
// 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_ad3552r_channel #(
parameter CHANNEL_ID = 32'h0,
parameter DDS_DISABLE = 0,
parameter DDS_TYPE = 1,
parameter DDS_CORDIC_DW = 16,
parameter DDS_CORDIC_PHASE_DW = 16
) (
// dac interface
input dac_clk,
input dac_rst,
output dac_data_valid,
output [15:0] dac_data,
// input sources
input [15:0] dma_data,
input [15:0] adc_data,
input valid_in_adc,
input valid_in_dma,
input dac_data_ready,
// processor interface
input dac_data_sync,
input dac_dfmt_type,
// bus interface
input up_rstn,
input up_clk,
input up_wreq,
input [13:0] up_waddr,
input [31:0] up_wdata,
output up_wack,
input up_rreq,
input [13:0] up_raddr,
output [31:0] up_rdata,
output up_rack
);
// internal signals
wire [15:0] formatted_dma_data;
wire [15:0] formatted_adc_data;
wire [ 3:0] dac_data_sel_s;
wire [15:0] dac_dds_data_s;
wire [15:0] dac_dds_scale_1_s;
wire [15:0] dac_dds_init_1_s;
wire [15:0] dac_dds_incr_1_s;
wire [15:0] dac_dds_scale_2_s;
wire [15:0] dac_dds_init_2_s;
wire [15:0] dac_dds_incr_2_s;
wire [15:0] dac_pat_data_1_s;
wire [15:0] dac_pat_data_2_s;
reg [15:0] ramp_pattern = 16'h0000;
reg ramp_valid = 1'b0;
reg [15:0] dac_data_int;
reg dac_data_valid_int;
assign dac_data = dac_data_int;
assign dac_data_valid = dac_data_valid_int;
assign formatted_dma_data [15] = dac_dfmt_type ^ dma_data[15];
assign formatted_dma_data [14:0] = dma_data[14:0];
assign formatted_adc_data [15] = dac_dfmt_type ^ adc_data[15];
assign formatted_adc_data [14:0] = adc_data[14:0];
always @ (*) begin
case(dac_data_sel_s)
4'h0 :
begin
dac_data_int = dac_dds_data_s;
dac_data_valid_int = 1'b1;
end
4'h2 :
begin
dac_data_int = formatted_dma_data;
dac_data_valid_int = valid_in_dma;
end
4'h3 :
begin
dac_data_int = 16'b0;
dac_data_valid_int = 1'b1;
end
4'h8 :
begin
dac_data_int = formatted_adc_data;
dac_data_valid_int = valid_in_adc;
end
4'hb :
begin
dac_data_int = ramp_pattern;
dac_data_valid_int = ramp_valid;
end
default :
begin
dac_data_int = 16'b0;
dac_data_valid_int = 1'b1;
end
endcase
end
// ramp generator
always @(posedge dac_clk) begin
ramp_valid <= 1'b1;
if(dac_data_ready == 1'b1) begin
ramp_pattern <= ramp_pattern + 1'b1;
end else begin
ramp_pattern <= ramp_pattern;
end
if(ramp_pattern == 16'hffff || dac_rst == 1'b1) begin
ramp_pattern <= 16'h0;
end
end
ad_dds #(
.DISABLE (DDS_DISABLE),
.DDS_DW (16),
.PHASE_DW (16),
.DDS_TYPE (DDS_TYPE),
.CORDIC_DW (DDS_CORDIC_DW),
.CORDIC_PHASE_DW (DDS_CORDIC_PHASE_DW),
.CLK_RATIO (1)
) i_dds (
.clk (dac_clk),
.dac_dds_format (dac_dfmt_type),
.dac_data_sync (dac_data_sync),
.dac_valid (dac_data_ready),
.tone_1_scale (dac_dds_scale_1_s),
.tone_2_scale (dac_dds_scale_2_s),
.tone_1_init_offset (dac_dds_init_1_s),
.tone_2_init_offset (dac_dds_init_2_s),
.tone_1_freq_word (dac_dds_incr_1_s),
.tone_2_freq_word (dac_dds_incr_2_s),
.dac_dds_data (dac_dds_data_s));
// single channel processor
up_dac_channel #(
.CHANNEL_ID(CHANNEL_ID),
.COMMON_ID(6'h01)
) dac_channel (
.dac_clk(dac_clk),
.dac_rst(dac_rst),
.dac_dds_scale_1(dac_dds_scale_1_s),
.dac_dds_init_1(dac_dds_init_1_s),
.dac_dds_incr_1(dac_dds_incr_1_s),
.dac_dds_scale_2(dac_dds_scale_2_s),
.dac_dds_init_2(dac_dds_init_2_s),
.dac_dds_incr_2(dac_dds_incr_2_s),
.dac_pat_data_1(dac_pat_data_1_s),
.dac_pat_data_2(dac_pat_data_2_s),
.dac_data_sel(dac_data_sel_s),
.dac_mask_enable(),
.dac_iq_mode(),
.dac_iqcor_enb(),
.dac_iqcor_coeff_1(),
.dac_iqcor_coeff_2(),
.dac_src_chan_sel(),
.up_usr_datatype_be(),
.up_usr_datatype_signed(),
.up_usr_datatype_shift(),
.up_usr_datatype_total_bits(),
.up_usr_datatype_bits(),
.up_usr_interpolation_m(),
.up_usr_interpolation_n(),
.dac_usr_datatype_be(1'd0),
.dac_usr_datatype_signed(1'd1),
.dac_usr_datatype_shift(8'd0),
.dac_usr_datatype_total_bits(8'd16),
.dac_usr_datatype_bits(8'd16),
.dac_usr_interpolation_m(16'd1),
.dac_usr_interpolation_n(16'd1),
.up_rstn(up_rstn),
.up_clk(up_clk),
.up_wreq(up_wreq),
.up_waddr(up_waddr),
.up_wdata(up_wdata),
.up_wack(up_wack),
.up_rreq(up_rreq),
.up_raddr(up_raddr),
.up_rdata(up_rdata),
.up_rack(up_rack));
endmodule

View File

@ -0,0 +1,261 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2022-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_ad3552r_core #(
parameter ID = 0,
parameter FPGA_TECHNOLOGY = 0,
parameter FPGA_FAMILY = 0,
parameter SPEED_GRADE = 0,
parameter DEV_PACKAGE = 0,
parameter DDS_DISABLE = 0,
parameter DDS_TYPE = 1,
parameter DDS_CORDIC_DW = 16,
parameter DDS_CORDIC_PHASE_DW = 16
) (
// dac interface
input dac_clk,
output dac_rst,
input [15:0] adc_data_in_a,
input [15:0] adc_data_in_b,
input [31:0] dma_data,
input adc_valid_in_a,
input adc_valid_in_b,
input valid_in_dma,
output [31:0] dac_data,
output dac_valid,
input dac_data_ready,
// output
output [ 7:0] address,
input if_busy,
input [23:0] data_read,
output [23:0] data_write,
output sdr_ddr_n,
output symb_8_16b,
output transfer_data,
output stream,
output dac_ext_sync_arm,
// processor interface
input up_rstn,
input up_clk,
input up_wreq,
input [13:0] up_waddr,
input [31:0] up_wdata,
output reg up_wack,
input up_rreq,
input [13:0] up_raddr,
output reg [31:0] up_rdata,
output reg up_rack
);
wire [31:0] up_rdata_0_s;
wire up_rack_0_s;
wire up_wack_0_s;
wire [31:0] up_rdata_1_s;
wire up_rack_1_s;
wire up_wack_1_s;
wire [31:0] up_rdata_s;
wire up_rack_s;
wire up_wack_s;
wire [15:0] dac_data_channel_0;
wire [15:0] dac_data_channel_1;
wire dac_valid_channel_0;
wire dac_valid_channel_1;
wire dac_rst_s;
wire [31:0] dac_data_control;
wire [31:0] dac_control;
wire dac_data_sync;
wire dac_dfmt_type;
// defaults
assign dac_rst = dac_rst_s;
assign dac_data = {dac_data_channel_1 ,dac_data_channel_0};
assign dac_valid = dac_valid_channel_0 | dac_valid_channel_1;
assign data_write = dac_data_control[23:0];
assign transfer_data = dac_control[0];
assign stream = dac_control[1];
assign address = dac_control[31:24];
// processor read interface
always @(negedge up_rstn or posedge up_clk) begin
if(up_rstn == 0) begin
up_rdata <= 'd0;
up_rack <= 'd0;
up_wack <= 'd0;
end else begin
up_rdata <= up_rdata_s | up_rdata_0_s | up_rdata_1_s;
up_rack <= up_rack_s | up_rack_0_s | up_rack_1_s;
up_wack <= up_wack_s | up_wack_0_s | up_wack_1_s;
end
end
// DAC CHANNEL 0
axi_ad3552r_channel #(
.CHANNEL_ID(0),
.DDS_DISABLE(DDS_DISABLE),
.DDS_TYPE(DDS_TYPE),
.DDS_CORDIC_DW(DDS_CORDIC_DW),
.DDS_CORDIC_PHASE_DW(DDS_CORDIC_PHASE_DW)
) axi_ad3552r_channel_0 (
.dac_clk(dac_clk),
.dac_rst(dac_rst_s),
.dac_data_valid(dac_valid_channel_0),
.dac_data(dac_data_channel_0),
.dma_data(dma_data[15:0]),
.dac_data_ready(dac_data_ready),
.adc_data(adc_data_in_a),
.valid_in_adc(adc_valid_in_a),
.valid_in_dma(valid_in_dma),
.dac_data_sync(dac_data_sync),
.dac_dfmt_type(dac_dfmt_type),
.up_rstn(up_rstn),
.up_clk(up_clk),
.up_wreq(up_wreq),
.up_waddr(up_waddr),
.up_wdata(up_wdata),
.up_wack(up_wack_0_s),
.up_rreq(up_rreq),
.up_raddr(up_raddr),
.up_rdata(up_rdata_0_s),
.up_rack(up_rack_0_s));
// DAC CHANNEL 1
axi_ad3552r_channel #(
.CHANNEL_ID(1),
.DDS_DISABLE(DDS_DISABLE),
.DDS_TYPE(DDS_TYPE),
.DDS_CORDIC_DW(DDS_CORDIC_DW),
.DDS_CORDIC_PHASE_DW(DDS_CORDIC_PHASE_DW)
) axi_ad3552r_channel_1(
.dac_clk(dac_clk),
.dac_rst(dac_rst_s),
.dac_data_valid(dac_valid_channel_1),
.dac_data(dac_data_channel_1),
.dma_data(dma_data[31:16]),
.dac_data_ready(dac_data_ready),
.adc_data(adc_data_in_b),
.valid_in_adc(adc_valid_in_b),
.valid_in_dma(valid_in_dma),
.dac_data_sync(dac_data_sync),
.dac_dfmt_type(dac_dfmt_type),
.up_rstn(up_rstn),
.up_clk(up_clk),
.up_wreq(up_wreq),
.up_waddr(up_waddr),
.up_wdata(up_wdata),
.up_wack(up_wack_1_s),
.up_rreq(up_rreq),
.up_raddr(up_raddr),
.up_rdata(up_rdata_1_s),
.up_rack(up_rack_1_s));
// dac common processor interface
up_dac_common #(
.ID(ID),
.FPGA_TECHNOLOGY(FPGA_TECHNOLOGY),
.FPGA_FAMILY(FPGA_FAMILY),
.SPEED_GRADE(SPEED_GRADE),
.DEV_PACKAGE(DEV_PACKAGE),
.COMMON_ID(6'h00)
) axi_ad3552r_common_core (
.mmcm_rst(),
.dac_clk(dac_clk),
.dac_rst(dac_rst_s),
.dac_num_lanes(),
.dac_sdr_ddr_n(sdr_ddr_n),
.dac_symb_op(),
.dac_symb_8_16b(symb_8_16b),
.dac_sync(dac_data_sync),
.dac_ext_sync_arm(dac_ext_sync_arm),
.dac_ext_sync_disarm(),
.dac_ext_sync_manual_req(),
.dac_frame(),
.dac_clksel(),
.dac_custom_wr(dac_data_control),
.dac_custom_rd({8'b0, data_read}),
.dac_custom_control(dac_control),
.dac_status_if_busy(if_busy),
.dac_par_type(),
.dac_par_enb(),
.dac_r1_mode(),
.dac_datafmt(dac_dfmt_type),
.dac_datarate(),
.dac_status(),
.dac_sync_in_status(),
.dac_status_unf(),
.dac_clk_ratio(32'd1),
.up_dac_ce(),
.up_pps_rcounter(32'd0),
.up_pps_status(1'd0),
.up_pps_irq_mask(),
.up_dac_r1_mode(),
.up_drp_sel(),
.up_drp_wr(),
.up_drp_addr(),
.up_drp_wdata() ,
.up_drp_rdata(32'd0),
.up_drp_ready(1'd1),
.up_drp_locked(1'd1),
.up_usr_chanmax(),
.dac_usr_chanmax(8'd1),
.up_dac_gpio_in(32'd0),
.up_dac_gpio_out(),
.up_rstn(up_rstn),
.up_clk(up_clk),
.up_wreq(up_wreq),
.up_waddr(up_waddr),
.up_wdata(up_wdata),
.up_wack(up_wack_s),
.up_rreq(up_rreq),
.up_raddr(up_raddr),
.up_rdata(up_rdata_s),
.up_rack (up_rack_s));
endmodule

View File

@ -0,0 +1,316 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2022-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_ad3552r_if (
input clk_in, // 120MHz
input reset_in,
input [31:0] dac_data,
input dac_data_valid,
input dac_data_valid_ext,
output dac_data_ready,
input [ 7:0] address,
input [23:0] data_write,
input sdr_ddr_n,
input symb_8_16b,
input transfer_data,
input stream,
input external_sync,
input external_sync_arm,
output if_busy,
output sync_ext_device,
output reg [23:0] data_read,
// DAC control signals
output sclk,
output reg csn,
input [ 3:0] sdio_i,
output [ 3:0] sdio_o,
output sdio_t
);
wire transfer_data_s;
wire start_synced;
wire [31:0] dac_data_int;
wire dac_data_valid_synced;
wire external_sync_s;
reg [55:0] transfer_reg = 56'h0;
reg [15:0] counter = 16'h0;
reg [ 2:0] transfer_state = 0;
reg [ 2:0] transfer_state_next = 0;
reg cycle_done = 1'b0;
reg transfer_step = 1'b0;
reg sclk_ddr = 1'b0;
reg full_speed = 1'b0;
reg transfer_data_d = 1'b0;
reg transfer_data_dd = 1'b0;
reg [ 3:0] valid_captured_d = 4'b0;
reg data_r_wn = 1'b0;
reg valid_captured = 1'b0;
reg start_transfer = 1'b0;
reg if_busy_reg = 1'b0;
reg dac_data_ready_s = 1'b0;
reg external_sync_arm_reg = 1'b0;
reg external_sync_reg = 1'b0;
localparam [ 2:0] IDLE = 3'h0,
CS_LOW = 3'h1,
WRITE_ADDRESS = 3'h2,
TRANSFER_REGISTER = 3'h3,
READ_REGISTER = 3'h4,
STREAM = 3'h5,
CS_HIGH = 3'h6;
assign if_busy = if_busy_reg;
// transform the transfer data rising edge into a pulse
assign transfer_data_s = transfer_data_d & ~transfer_data_dd;
// start the data stream transfer after valid has been captured
assign start_synced = valid_captured_d[1] & start_transfer & stream;
assign sync_ext_device = start_synced ;
// use dac_data valid from an external source only if external_sync_arm_reg is 1
assign dac_data_valid_synced = (external_sync_arm_reg == 1'b1) ? (dac_data_valid & dac_data_valid_ext) : dac_data_valid ;
assign dac_data_ready = dac_data_ready_s & dac_data_valid_synced;
assign dac_data_int = dac_data;
// sync the data only if the synchronizations has been armed in software
assign external_sync_s = ~external_sync_arm_reg | external_sync_reg;
always @(posedge clk_in) begin
if(reset_in == 1'b1) begin
transfer_data_d <= 'd0;
transfer_data_dd <= 'd0;
valid_captured_d <= 4'b0;
valid_captured <= 1'b0;
end else begin
transfer_data_d <= transfer_data;
transfer_data_dd <= transfer_data_d;
valid_captured_d <= {valid_captured_d[2:0], valid_captured};
end
if(transfer_state == CS_HIGH || stream == 1'b0) begin
start_transfer <= 1'b0;
valid_captured <= 1'b0;
valid_captured_d <= 4'b0;
end
// pulse to level conversion
if(external_sync_arm == 1'b1) begin
external_sync_arm_reg <= 1'b1;
end
if(external_sync == 1'b1) begin
external_sync_reg <= 1'b1;
end
if(transfer_state == CS_HIGH) begin
external_sync_arm_reg <= 1'b0;
external_sync_reg <= 1'b0;
end
if(dac_data_valid == 1'b1 && start_transfer == 1'b1) begin
valid_captured <= 1'b1;
end
if(transfer_data == 1'b1) begin
start_transfer <= 1'b1;
end
end
always @(posedge clk_in) begin
if (reset_in == 1'b1) begin
transfer_state <= IDLE;
end else begin
transfer_state <= transfer_state_next;
end
end
// FSM next state logic
always @(*) begin
case (transfer_state)
IDLE : begin
// goes in to the next state only if the control is to transfer register or synced transfer(if it's armed in software)
transfer_state_next = ((transfer_data_s == 1'b1 && stream == 1'b0) || (start_synced == 1'b1 && external_sync_s)) ? CS_LOW : IDLE;
csn = 1'b1;
transfer_step = 0;
cycle_done = 0;
end
CS_LOW : begin
// brings CS down
// loads all configuration
// puts data on the SDIO pins
// needs 5 ns before risedge of the clock
transfer_state_next = WRITE_ADDRESS;
csn = 1'b0;
transfer_step = 0;
cycle_done = 0;
end
WRITE_ADDRESS : begin
// writes the address
// it works either at full speed (60 MHz) when streaming or normal
// speed (15 MHz)
// full speed - 2 clock cycles
// half speed 8 clock cycles
cycle_done = full_speed ? (counter == 16'h3) : (counter == 16'hf);
transfer_state_next = cycle_done ? (stream ? STREAM : TRANSFER_REGISTER) : WRITE_ADDRESS ;
csn = 1'b0;
// in streaming, change data on falledge. On regular transfer, change data on negedge.
//A single step should be done for 8 bit addressing
transfer_step = full_speed ? (counter[0]== 1'h1) : ((counter[4:0] == 5'h5));
end
TRANSFER_REGISTER : begin
// always works at 15 MHz
// can be DDR or SDR
cycle_done = sdr_ddr_n ? (symb_8_16b ? (counter == 16'h10) : (counter == 16'h20)) :
(symb_8_16b ? (counter == 16'h09) : (counter == 16'h11));
transfer_state_next = cycle_done ? CS_HIGH : TRANSFER_REGISTER;
csn = 1'b0;
// in DDR mode, change data on falledge
transfer_step = sdr_ddr_n ? (counter[2:0] == 3'h0) : (counter[1:0] == 2'h0);
end
STREAM : begin
// can be DDR or SDR
// in DDR mode needs to be make sure the clock and data is shifted by 2 ns
cycle_done = stream ? (sdr_ddr_n ? (counter == 16'h0f) : (counter == 16'h7)):
(sdr_ddr_n ? (counter == 16'h10) : (counter == 16'h7));
transfer_state_next = (stream && external_sync_s) ? STREAM: ((cycle_done || external_sync_s == 1'b0) ? CS_HIGH :STREAM);
csn = 1'b0;
transfer_step = sdr_ddr_n ? counter[0] : 1'b1;
end
CS_HIGH : begin
cycle_done = 1'b1;
transfer_state_next = cycle_done ? IDLE : CS_HIGH;
csn = 1'b1;
transfer_step = 0;
end
default : begin
cycle_done = 0;
transfer_state_next = IDLE;
csn = 1'b1;
transfer_step = 0;
end
endcase
end
// counter is used to time all states
// depends on number of clock cycles per phase
always @(posedge clk_in) begin
if (transfer_state == IDLE || reset_in == 1'b1) begin
counter <= 'b0;
end else if (transfer_state == WRITE_ADDRESS | transfer_state == TRANSFER_REGISTER | transfer_state == STREAM) begin
if (cycle_done) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
end
always @(negedge clk_in) begin
if (transfer_state == STREAM | transfer_state == WRITE_ADDRESS) begin
sclk_ddr <= !sclk_ddr;
end else begin
sclk_ddr <= 0;
end
end
// selection between 60 MHz and 15 MHz
assign sclk = full_speed ? (sdr_ddr_n ? counter[0] : sclk_ddr) : counter[2];
always @(posedge clk_in) begin
if (transfer_state == CS_LOW) begin
data_r_wn <= address[7];
end else if (transfer_state == CS_HIGH) begin
data_r_wn <=1'b0;
end
if (transfer_state == STREAM) begin
if (cycle_done == 1'b1) begin
dac_data_ready_s <= stream;
end else begin
dac_data_ready_s <= 1'b0;
end
end else begin
dac_data_ready_s <= 1'b0;
end
if (transfer_state == CS_LOW) begin
full_speed = stream;
if(stream) begin
transfer_reg <= {address,dac_data_int, 16'h0};
end else begin
transfer_reg <= {address,data_write, 24'h0};
end
end else if ((transfer_state == STREAM & cycle_done) || (transfer_state != STREAM && transfer_state_next == STREAM)) begin
transfer_reg <= {dac_data_int, 24'h0};
end else if (transfer_step && transfer_state != CS_HIGH) begin
transfer_reg <= {transfer_reg[51:0], sdio_i};
end
if (transfer_state == CS_HIGH) begin
if (symb_8_16b == 1'b0) begin
data_read <= {8'h0,transfer_reg[15:0]};
end else begin
data_read <= {16'h0,transfer_reg[7:0]};
end
end else begin
data_read <= data_read;
end
if (transfer_state == CS_HIGH || transfer_state == IDLE) begin
if_busy_reg <= 1'b0;
end else begin
if_busy_reg <= 1'b1;
end
end
// address[7] is r_wn : depends also on the state machine, input only when
// in TRANSFER register mode
assign sdio_t = (data_r_wn & transfer_state == TRANSFER_REGISTER);
assign sdio_o = transfer_reg[55:52];
endmodule

View File

@ -0,0 +1,7 @@
#!/bin/bash
SOURCE="$0.v"
SOURCE+=" axi_ad3552r_if.v"
cd `dirname $0`
source ../common/tb/run_tb.sh

View File

@ -0,0 +1,239 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2022-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_ad3552r_if_tb;
parameter VCD_FILE = "axi_ad3552r_if_tb.vcd";
`define TIMEOUT 9000
`include "../common/tb/tb_base.v"
wire [ 23:0] data_read;
wire dac_sclk;
wire dac_csn;
wire dac_data_ready;
wire [ 3:0] sdio_i;
wire [ 3:0] sdio_o;
wire sdio_t;
wire [31:0] dac_data_final;
wire [ 3:0] readback_data_shift;
wire [ 4:0] data_increment_valid;
wire if_busy;
reg [ 7:0] address_write = 8'b0;
reg dac_clk = 1'b0;
reg reset_in = 1'b1;
reg transfer_data = 1'b0;
reg sdr_ddr_n = 1'b1;
reg reg_8b_16bn = 1'b0;
reg stream = 1'b0;
reg [23:0] data_write = 24'h0;
reg dac_data_valid = 1'b0;
reg [ 3:0] shift_count = 4'b0;
reg [31:0] transfer_reg = 32'h89abcdef;
reg [ 4:0] valid_counter = 5'b0;
reg [31:0] dac_data = 32'b0;
always #4 dac_clk <= ~dac_clk;
initial begin
#100 reset_in = 1'b0;
// Write 8 bit SDR
address_write = 8'h2c;
data_write = 24'hab0000;
sdr_ddr_n = 1'b1;
reg_8b_16bn = 1'b1;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
// Read 8 bit SDR
address_write = 8'hac;
data_write = 24'h000000;
sdr_ddr_n = 1'b1;
reg_8b_16bn = 1'b1;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
// Write 16 bit SDR
address_write = 8'h2c;
data_write = 24'h123400;
sdr_ddr_n = 1'b1;
reg_8b_16bn = 1'b0;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
// Read 16 bit SDR
address_write = 8'hac;
data_write = 24'h000000;
sdr_ddr_n = 1'b1;
reg_8b_16bn = 1'b0;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
#500;
// Write 8 bit DDR
address_write = 8'h2c;
data_write = 24'h120000;
sdr_ddr_n = 1'b0;
reg_8b_16bn = 1'b1;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
// Read 8 bit DDR
address_write = 8'hac;
data_write = 24'h000000;
sdr_ddr_n = 1'b0;
reg_8b_16bn = 1'b1;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
// Write 16 bit DDR
address_write = 8'h2c;
data_write = 24'h123400;
sdr_ddr_n = 1'b0;
reg_8b_16bn = 1'b0;
stream = 1'b0;
transfer_data = 1'b1;
#100 transfer_data = 1'b0;
// Read 16 bit DDR
address_write = 8'hac;
data_write = 24'h000000;
sdr_ddr_n = 1'b0;
reg_8b_16bn = 1'b0;
stream = 1'b0;
#500 transfer_data = 1'b1;
#100 transfer_data = 1'b0;
#500;
// Stream SDR
address_write = 8'h2c;
sdr_ddr_n = 1'b1;
reg_8b_16bn = 1'b0;
stream = 1'b1;
transfer_data = 1'b1;
#100 transfer_data = 1'b0;
#1000 stream = 1'b0;
#500;
// Stream DDR
address_write = 8'h2c;
reg_8b_16bn = 1'b1;
sdr_ddr_n = 1'b0;
stream = 1'b1;
transfer_data = 1'b1;
#100 transfer_data = 1'b0;
#1000 stream = 1'b0;
end
// data is incremented at each complete cycle
assign dac_data_final = (stream == 1'b1) ? dac_data : data_write;
assign data_increment_valid = (sdr_ddr_n ) ? 5'd16: 5'h8;
always @(posedge dac_clk) begin
if (valid_counter == data_increment_valid) begin
dac_data <= dac_data + 32'h00010002;
valid_counter <= 3'b0;
dac_data_valid <= 1'b1;
end else begin
dac_data <= dac_data;
valid_counter <= valid_counter + 3'b1;
dac_data_valid <= 1'b0;
end
end
// data is circullary shifted at every sampling edge
assign readback_data_shift = (sdr_ddr_n ) ? 4'h8 : 4'h4;
assign sdio_i = (sdio_t === 1'b1) ? transfer_reg[31:28] : 4'b0;
always @(posedge dac_clk) begin
if (shift_count == readback_data_shift) begin
transfer_reg <= {transfer_reg[27:0],transfer_reg[31:28]};
end else if (sdio_t === 1'b1) begin
transfer_reg <= transfer_reg;
end
if (shift_count == readback_data_shift || dac_csn == 1'b1) begin
shift_count <= 3'b0;
end else if (sdio_t === 1'b1) begin
shift_count <= shift_count + 3'b1;
end
end
axi_ad3552r_if axi_ad3552r_interface (
.clk_in(dac_clk),
.reset_in(reset_in),
.dac_data(dac_data_final),
.dac_data_valid(dac_data_valid),
.address(address_write),
.data_read(data_read),
.data_write(data_write),
.sdr_ddr_n(sdr_ddr_n),
.symb_8_16b(reg_8b_16bn),
.transfer_data(transfer_data),
.stream(stream),
.dac_data_ready(dac_data_ready),
.if_busy(if_busy),
.sclk(dac_sclk),
.csn(dac_csn),
.sdio_i(sdio_i),
.sdio_o(sdio_o),
.sdio_t(sdio_t));
endmodule

View File

@ -0,0 +1,51 @@
###############################################################################
## Copyright (C) 2022-2023 Analog Devices, Inc. All rights reserved.
### SPDX short identifier: ADIBSD
###############################################################################
source ../../scripts/adi_env.tcl
source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl
adi_ip_create axi_ad3552r
adi_ip_files axi_ad3552r [list \
"$ad_hdl_dir/library/xilinx/common/ad_mul.v" \
"$ad_hdl_dir/library/common/ad_rst.v" \
"$ad_hdl_dir/library/common/up_axi.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_dac_common.v" \
"$ad_hdl_dir/library/common/up_dac_channel.v" \
"$ad_hdl_dir/library/common/ad_dds_cordic_pipe.v" \
"$ad_hdl_dir/library/common/ad_dds_sine_cordic.v" \
"$ad_hdl_dir/library/common/ad_dds_sine.v" \
"$ad_hdl_dir/library/common/ad_dds_2.v" \
"$ad_hdl_dir/library/common/ad_dds_1.v" \
"$ad_hdl_dir/library/common/ad_dds.v" \
"$ad_hdl_dir/library/common/ad_addsub.v" \
"$ad_hdl_dir/library/xilinx/common/up_xfer_cntrl_constr.xdc" \
"$ad_hdl_dir/library/xilinx/common/ad_rst_constr.xdc" \
"$ad_hdl_dir/library/xilinx/common/up_xfer_status_constr.xdc" \
"$ad_hdl_dir/library/xilinx/common/up_clock_mon_constr.xdc" \
"axi_ad3552r_channel.v" \
"axi_ad3552r_core.v" \
"axi_ad3552r_if.v" \
"axi_ad3552r.v" ]
adi_ip_properties axi_ad3552r
adi_init_bd_tcl
adi_ip_bd axi_ad3552r "bd/bd.tcl"
set cc [ipx::current_core]
set_property company_url {https://wiki.analog.com/resources/fpga/docs/axi_ad3552r} $cc
set_property driver_value 0 [ipx::get_ports *dac* -of_objects $cc]
set_property driver_value 0 [ipx::get_ports *data* -of_objects $cc]
set_property driver_value 0 [ipx::get_ports *valid* -of_objects $cc]
ipx::infer_bus_interface dac_clk xilinx.com:signal:clock_rtl:1.0 $cc
adi_add_auto_fpga_spec_params
ipx::create_xgui_files $cc
ipx::save_core $cc