diff --git a/library/Makefile b/library/Makefile index 2b5907f08..6f85dfcbc 100644 --- a/library/Makefile +++ b/library/Makefile @@ -60,6 +60,7 @@ clean: $(MAKE) -C axi_mc_controller clean $(MAKE) -C axi_mc_current_monitor clean $(MAKE) -C axi_mc_speed clean + $(MAKE) -C axi_pulse_gen clean $(MAKE) -C axi_rd_wr_combiner clean $(MAKE) -C axi_spdif_rx clean $(MAKE) -C axi_spdif_tx clean @@ -168,6 +169,7 @@ lib: $(MAKE) -C axi_mc_controller $(MAKE) -C axi_mc_current_monitor $(MAKE) -C axi_mc_speed + $(MAKE) -C axi_pulse_gen $(MAKE) -C axi_rd_wr_combiner $(MAKE) -C axi_spdif_rx $(MAKE) -C axi_spdif_tx diff --git a/library/axi_ad5766/axi_ad5766.v b/library/axi_ad5766/axi_ad5766.v index 558585a13..cf2f89076 100644 --- a/library/axi_ad5766/axi_ad5766.v +++ b/library/axi_ad5766/axi_ad5766.v @@ -298,10 +298,10 @@ module axi_ad5766 #( util_pulse_gen #(.PULSE_WIDTH(1)) i_trigger_gen ( .clk (spi_clk), .rstn (dac_rstn_s), + .pulse_width (1'b1), .pulse_period (pulse_period_s), - .pulse_period_en (1'b1), + .load_config (1'b1), .pulse (trigger_s) - ); // offset of the sequencer registers are 8'h40 diff --git a/library/axi_pulse_gen/Makefile b/library/axi_pulse_gen/Makefile new file mode 100644 index 000000000..daa0c6e05 --- /dev/null +++ b/library/axi_pulse_gen/Makefile @@ -0,0 +1,20 @@ +#################################################################################### +## Copyright 2018(c) Analog Devices, Inc. +## Auto-generated, do not modify! +#################################################################################### + +LIBRARY_NAME := axi_pulse_gen + +GENERIC_DEPS += ../common/ad_rst.v +GENERIC_DEPS += ../common/up_axi.v +GENERIC_DEPS += ../common/util_pulse_gen.v +GENERIC_DEPS += axi_pulse_gen.v +GENERIC_DEPS += axi_pulse_gen_regmap.v + +XILINX_DEPS += ../xilinx/common/ad_rst_constr.xdc +XILINX_DEPS += axi_pulse_gen_constr.ttcl +XILINX_DEPS += axi_pulse_gen_ip.tcl + +XILINX_LIB_DEPS += util_cdc + +include ../scripts/library.mk diff --git a/library/axi_pulse_gen/axi_pulse_gen.v b/library/axi_pulse_gen/axi_pulse_gen.v new file mode 100644 index 000000000..f4c679d0d --- /dev/null +++ b/library/axi_pulse_gen/axi_pulse_gen.v @@ -0,0 +1,165 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2019 (c) 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: +// +// +// 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_pulse_gen #( + + parameter ID = 0, + parameter [0:0] ASYNC_CLK_EN = 1, + parameter PULSE_WIDTH = 7, + parameter PULSE_PERIOD = 10 )( + + // 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, + input ext_clk, + output pulse); + + // local parameters + + localparam [31:0] CORE_VERSION = {16'h0000, /* MAJOR */ + 8'h01, /* MINOR */ + 8'h00}; /* PATCH */ // 0.01.0 + localparam [31:0] CORE_MAGIC = 32'h504c5347; // PLSG + + // internal signals + + wire clk; + wire up_clk; + wire up_rstn; + wire up_rreq_s; + wire up_wack_s; + wire up_rack_s; + wire [13:0] up_raddr_s; + wire [31:0] up_rdata_s; + wire up_wreq_s; + wire [13:0] up_waddr_s; + wire [31:0] up_wdata_s; + wire [31:0] pulse_width_s; + wire [31:0] pulse_period_s; + wire load_config_s; + wire pulse_gen_resetn; + + assign up_clk = s_axi_aclk; + assign up_rstn = s_axi_aresetn; + + axi_pulse_gen_regmap #( + .ID (ID), + .ASYNC_CLK_EN (ASYNC_CLK_EN), + .CORE_MAGIC (CORE_MAGIC), + .CORE_VERSION (CORE_VERSION), + .PULSE_WIDTH (PULSE_WIDTH), + .PULSE_PERIOD (PULSE_PERIOD)) + i_regmap ( + .ext_clk (ext_clk), + .clk (clk), + .pulse_gen_resetn (pulse_gen_resetn), + .pulse_width (pulse_width_s), + .pulse_period (pulse_period_s), + .load_config (load_config_s), + .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)); + + util_pulse_gen #( + .PULSE_WIDTH(PULSE_WIDTH), + .PULSE_PERIOD(PULSE_PERIOD)) + util_pulse_gen_i( + .clk (clk), + .rstn (pulse_gen_resetn), + .pulse_width (pulse_width_s), + .pulse_period (pulse_period_s), + .load_config (load_config_s), + .pulse (pulse)); + + up_axi #( + .ADDRESS_WIDTH(14)) + 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 diff --git a/library/axi_pulse_gen/axi_pulse_gen_constr.ttcl b/library/axi_pulse_gen/axi_pulse_gen_constr.ttcl new file mode 100644 index 000000000..79f32ef7c --- /dev/null +++ b/library/axi_pulse_gen/axi_pulse_gen_constr.ttcl @@ -0,0 +1,36 @@ +<: set ComponentName [getComponentNameString] :> +<: setOutputDirectory "./" :> +<: setFileName [ttcl_add $ComponentName "_constr"] :> +<: setFileExtension ".xdc" :> +<: setFileProcessingOrder late :> +<: set async_clock [getBooleanValue "ASYNC_CLK_EN"] :> + +## False path definitions for ASYNC mode +<: if { $async_clock } { :> + +set_property ASYNC_REG TRUE \ + [get_cells -hier {*cdc_sync_stage1_reg*}] \ + [get_cells -hier {*cdc_sync_stage2_reg*}] + + ## it is constrained to a 250MHz external clock, it can be relaxed if required + ## max skew must be num_of_synchronization_stages x destination_clock_period_ns + set_bus_skew -from [get_cells -hierarchical * -filter {NAME=~*i_pulse_period_sync/cdc_hold_reg*}] \ + -to [get_cells -hierarchical * -filter {NAME=~*i_pulse_period_sync/out_data_reg*}] \ + 8 + set_bus_skew -from [get_cells -hierarchical * -filter {NAME=~*i_pulse_width_sync/cdc_hold_reg*}] \ + -to [get_cells -hierarchical * -filter {NAME=~*i_pulse_width_sync/out_data_reg*}] \ + 8 + + set_false_path \ + -from [get_pins -hierarchical * -filter {NAME=~*i_pulse_period_sync/out_toggle_d1_reg/C}] \ + -to [get_pins -hierarchical * -filter {NAME=~*i_pulse_period_sync/i_sync_in/cdc_sync_stage1_reg[0]/D}] + + set_false_path \ + -from [get_pins -hierarchical * -filter {NAME=~*i_pulse_width_sync/out_toggle_d1_reg/C}] \ + -to [get_pins -hierarchical * -filter {NAME=~*i_pulse_width_sync/i_sync_in/cdc_sync_stage1_reg[0]/D}] + + set_false_path \ + -from [get_pins -hierarchical * -filter {NAME=~*i_load_config_sync/out_toggle_d1_reg/C}] \ + -to [get_pins -hierarchical * -filter {NAME=~*i_load_config_sync/i_sync_in/cdc_sync_stage1_reg[0]/D}] + +<: } :> diff --git a/library/axi_pulse_gen/axi_pulse_gen_ip.tcl b/library/axi_pulse_gen/axi_pulse_gen_ip.tcl new file mode 100644 index 000000000..f2a6d801c --- /dev/null +++ b/library/axi_pulse_gen/axi_pulse_gen_ip.tcl @@ -0,0 +1,99 @@ +# ip + +source ../scripts/adi_env.tcl +source $ad_hdl_dir/library/scripts/adi_ip.tcl + +adi_ip_create axi_pulse_gen +adi_ip_files axi_pulse_gen [list \ + "$ad_hdl_dir/library/common/ad_rst.v" \ + "$ad_hdl_dir/library/common/up_axi.v" \ + "$ad_hdl_dir/library/xilinx/common/ad_rst_constr.xdc" \ + "$ad_hdl_dir/library/common/util_pulse_gen.v" \ + "axi_pulse_gen_constr.ttcl" \ + "axi_pulse_gen_regmap.v" \ + "axi_pulse_gen.v"] + +adi_ip_properties axi_pulse_gen +adi_ip_ttcl axi_pulse_gen "axi_pulse_gen_constr.ttcl" + +adi_ip_add_core_dependencies { \ + analog.com:user:util_cdc:1.0 \ +} + + +set cc [ipx::current_core] + +set_property display_name "ADI AXI Pulse Generator" $cc +set_property description "ADI AXI Pulse Generator" $cc + +## define ext_clk port as a clock interface +adi_add_bus ext_clk slave \ + "xilinx.com:signal:clock_rtl:1.0" \ + "xilinx.com:signal:clock:1.0" \ + [list {"ext_clk" "CLK"} ] + +adi_set_ports_dependency "ext_clk" \ + "(spirit:decode(id('MODELPARAM_VALUE.ASYNC_CLK_EN')) = 1)" 0 + +## Parameter validation + +set_property -dict [list \ + "value_format" "bool" \ + "value" "true" \ + ] \ +[ipx::get_user_parameters ASYNC_CLK_EN -of_objects $cc] + +set_property -dict [list \ + "value_format" "bool" \ + "value" "true" \ + ] \ +[ipx::get_hdl_parameters ASYNC_CLK_EN -of_objects $cc] + +set_property -dict [list \ + "value_validation_type" "range_long" \ + "value_validation_range_minimum" "0" \ + "value_validation_range_maximum" "2147483647" \ + ] \ +[ipx::get_user_parameters PULSE_WIDTH -of_objects $cc] + +set_property -dict [list \ + "value_validation_type" "range_long" \ + "value_validation_range_minimum" "0" \ + "value_validation_range_maximum" "2147483647" \ + ] \ +[ipx::get_user_parameters PULSE_PERIOD -of_objects $cc] + +## Customize XGUI layout + +## Remove the automatically generated GUI page +ipgui::remove_page -component $cc [ipgui::get_pagespec -name "Page 0" -component $cc] +ipx::save_core $cc + +## Create a new GUI page + +ipgui::add_page -name {AXI Pulse Generator} -component $cc -display_name {AXI Pulse Generator} +set page0 [ipgui::get_pagespec -name "AXI Pulse Generator" -component $cc] + +ipgui::add_param -name "ASYNC_CLK_EN" -component $cc -parent $page0 +set_property -dict [list \ + "display_name" "ASYNC_CLK_EN" \ + "tooltip" "External clock for the counter" \ + "widget" "checkBox" \ +] [ipgui::get_guiparamspec -name "ASYNC_CLK_EN" -component $cc] + +ipgui::add_param -name "PULSE_WIDTH" -component $cc -parent $page0 +set_property -dict [list \ + "display_name" "Pulse width" \ + "tooltip" "Pulse width of the generated signal. The unit interval is the system or external clock period." \ +] [ipgui::get_guiparamspec -name "PULSE_WIDTH" -component $cc] + +ipgui::add_param -name "PULSE_PERIOD" -component $cc -parent $page0 +set_property -dict [list \ + "display_name" "Pulse period" \ + "tooltip" "Period of the generated signal. The unit interval is the system or external clock period." \ +] [ipgui::get_guiparamspec -name "PULSE_PERIOD" -component $cc] + +## Save the modifications + +ipx::create_xgui_files $cc +ipx::save_core $cc diff --git a/library/axi_pulse_gen/axi_pulse_gen_regmap.v b/library/axi_pulse_gen/axi_pulse_gen_regmap.v new file mode 100644 index 000000000..947b32bf5 --- /dev/null +++ b/library/axi_pulse_gen/axi_pulse_gen_regmap.v @@ -0,0 +1,180 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2019 (c) 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: +// +// +// 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_pulse_gen_regmap #( + + parameter ID = 0, + parameter [31:0] CORE_MAGIC = 0, + parameter [31:0] CORE_VERSION = 0, + parameter [ 0:0] ASYNC_CLK_EN = 1, + parameter PULSE_WIDTH = 7, + parameter PULSE_PERIOD = 10 )( + + // external clock + + input ext_clk, + + // control and status signals + + output clk, + output pulse_gen_resetn, + output [31:0] pulse_width, + output [31:0] pulse_period, + output load_config, + + // 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 +); + + // internal registers + + reg [31:0] up_scratch = 'd0; + reg [31:0] up_pulse_width = 'd0; + reg [31:0] up_pulse_period = 'd0; + reg up_load_config = 1'b0; + reg up_reset; + + always @(posedge up_clk) begin + if (up_rstn == 0) begin + up_wack <= 'd0; + up_scratch <= 'd0; + up_pulse_period <= PULSE_PERIOD; + up_pulse_width <= PULSE_WIDTH; + up_load_config <= 1'b0; + up_reset <= 1'b1; + end else begin + up_wack <= up_wreq; + if ((up_wreq == 1'b1) && (up_waddr[3:0] == 4'h2)) begin + up_scratch <= up_wdata; + end + if ((up_wreq == 1'b1) && (up_waddr[3:0] == 4'h4)) begin + up_reset <= up_wdata[0]; + up_load_config <= up_wdata[1]; + end else begin + up_load_config <= 1'b0; + end + if ((up_wreq == 1'b1) && (up_waddr[3:0] == 4'h5)) begin + up_pulse_period <= up_wdata; + end + if ((up_wreq == 1'b1) && (up_waddr[3:0] == 4'h6)) begin + up_pulse_width <= up_wdata; + end + end + end + + always @(posedge up_clk) begin + if (up_rstn == 0) begin + up_rack <= 'd0; + up_rdata <= 'd0; + end else begin + up_rack <= up_rreq; + if (up_rreq == 1'b1) begin + case (up_raddr[3:0]) + 4'h0: up_rdata <= CORE_VERSION; + 4'h1: up_rdata <= ID; + 4'h2: up_rdata <= up_scratch; + 4'h3: up_rdata <= CORE_MAGIC; + 4'h4: up_rdata <= up_reset; + 4'h5: up_rdata <= up_pulse_period; + 4'h6: up_rdata <= up_pulse_width; + default: up_rdata <= 0; + endcase + end else begin + up_rdata <= 32'd0; + end + end + end + + generate + if (ASYNC_CLK_EN) begin : counter_external_clock + + assign clk = ext_clk; + + ad_rst i_d_rst_reg ( + .rst_async (up_reset), + .clk (clk), + .rstn (pulse_gen_resetn), + .rst ()); + + sync_data #( + .NUM_OF_BITS (32), + .ASYNC_CLK (1)) + i_pulse_period_sync ( + .in_clk (up_clk), + .in_data (up_pulse_period), + .out_clk (clk), + .out_data (pulse_period)); + + sync_data #( + .NUM_OF_BITS (32), + .ASYNC_CLK (1)) + i_pulse_width_sync ( + .in_clk (up_clk), + .in_data (up_pulse_width), + .out_clk (clk), + .out_data (pulse_width)); + + sync_event #( + .NUM_OF_EVENTS (1), + .ASYNC_CLK (1)) + i_load_config_sync ( + .in_clk (up_clk), + .in_event (up_load_config), + .out_clk (clk), + .out_event (load_config)); + + end else begin : counter_sys_clock // counter is running on system clk + + assign clk = up_clk; + assign pulse_gen_resetn = ~up_reset; + assign pulse_period = up_pulse_period; + assign pulse_width = up_pulse_width; + assign load_config = up_load_config; + + end + endgenerate + +endmodule diff --git a/library/common/util_pulse_gen.v b/library/common/util_pulse_gen.v index 93817e1b3..7a8cb9f43 100644 --- a/library/common/util_pulse_gen.v +++ b/library/common/util_pulse_gen.v @@ -42,8 +42,9 @@ module util_pulse_gen #( input clk, input rstn, + input [31:0] pulse_width, input [31:0] pulse_period, - input pulse_period_en, + input load_config, output reg pulse ); @@ -52,41 +53,58 @@ module util_pulse_gen #( reg [(PULSE_WIDTH-1):0] pulse_width_cnt = {PULSE_WIDTH{1'b1}}; reg [31:0] pulse_period_cnt = 32'h0; + reg [31:0] pulse_period_read = 32'b0; + reg [31:0] pulse_width_read = 32'b0; reg [31:0] pulse_period_d = 32'b0; + reg [31:0] pulse_width_d = 32'b0; wire end_of_period_s; // flop the desired period always @(posedge clk) begin - pulse_period_d <= (pulse_period_en) ? pulse_period : PULSE_PERIOD; + if (rstn == 1'b0) begin + pulse_period_d <= PULSE_PERIOD; + pulse_width_d <= PULSE_WIDTH; + pulse_period_read <= PULSE_PERIOD; + pulse_width_read <= PULSE_WIDTH; + end else begin + // latch the input period/width values + if (load_config) begin + pulse_period_read <= pulse_period; + pulse_width_read <= pulse_width; + end + // update the current period/width at the end of the period + if (end_of_period_s) begin + pulse_period_d <= pulse_period_read; + pulse_width_d <= pulse_width_read; + end + end end // a free running pulse generator always @(posedge clk) begin if (rstn == 1'b0) begin - pulse_period_cnt <= 32'h0; + pulse_period_cnt <= PULSE_PERIOD; end else begin - pulse_period_cnt <= (pulse_period_cnt == pulse_period_d) ? 32'b0 : (pulse_period_cnt + 1); + pulse_period_cnt <= (end_of_period_s) ? pulse_period_d : (pulse_period_cnt - 1'b1); end end + assign end_of_period_s = (pulse_period_cnt == 32'b0) ? 1'b1 : 1'b0; - assign end_of_period_s = (pulse_period_cnt == pulse_period_d) ? 1'b1 : 1'b0; // generate pulse with a specified width - always @(posedge clk) begin + always @ (posedge clk) begin if (rstn == 1'b0) begin - pulse_width_cnt <= 0; - pulse <= 0; + pulse <= 1'b0; + end else if (end_of_period_s) begin + pulse <= 1'b0; + end else if (pulse_period_cnt == pulse_width_d) begin + pulse <= 1'b1; end else begin - pulse_width_cnt <= (pulse == 1'b1) ? pulse_width_cnt + 1 : {PULSE_WIDTH{1'h0}}; - if(end_of_period_s == 1'b1) begin - pulse <= 1'b1; - end else if(pulse_width_cnt == {PULSE_WIDTH{1'b1}}) begin - pulse <= 1'b0; - end + pulse <= pulse; end end diff --git a/library/util_tdd_sync/util_tdd_sync.v b/library/util_tdd_sync/util_tdd_sync.v index 40ab10366..7c19a8078 100644 --- a/library/util_tdd_sync/util_tdd_sync.v +++ b/library/util_tdd_sync/util_tdd_sync.v @@ -67,8 +67,9 @@ module util_tdd_sync #( i_tdd_sync ( .clk (clk), .rstn (rstn), - .pulse_period (31'd0), - .pulse_period_en (1'd0), + .pulse_width (32'd0) + .pulse_period (32'd0), + .load_config (1'd0), .pulse (sync_internal) );