From 8a2b1dc6dc62875c3a4053c2abd432cb3b22f5b4 Mon Sep 17 00:00:00 2001 From: Alin-Tudor Sferle Date: Tue, 7 Nov 2023 10:45:14 +0200 Subject: [PATCH 1/4] axi_pwm_gen: Add support for 16 channels Signed-off-by: Alin-Tudor Sferle Signed-off-by: AndreiGrozav --- library/axi_pwm_gen/Makefile | 4 +- library/axi_pwm_gen/axi_pwm_gen.sv | 394 ++++++++++++++++++++++ library/axi_pwm_gen/axi_pwm_gen.v | 356 ------------------- library/axi_pwm_gen/axi_pwm_gen_1.v | 4 +- library/axi_pwm_gen/axi_pwm_gen_hw.tcl | 42 ++- library/axi_pwm_gen/axi_pwm_gen_ip.tcl | 10 +- library/axi_pwm_gen/axi_pwm_gen_regmap.sv | 202 +++++++++++ library/axi_pwm_gen/axi_pwm_gen_regmap.v | 274 --------------- 8 files changed, 644 insertions(+), 642 deletions(-) create mode 100644 library/axi_pwm_gen/axi_pwm_gen.sv delete mode 100644 library/axi_pwm_gen/axi_pwm_gen.v create mode 100644 library/axi_pwm_gen/axi_pwm_gen_regmap.sv delete mode 100644 library/axi_pwm_gen/axi_pwm_gen_regmap.v diff --git a/library/axi_pwm_gen/Makefile b/library/axi_pwm_gen/Makefile index 6c08f9c4f60..e79670d4b13 100644 --- a/library/axi_pwm_gen/Makefile +++ b/library/axi_pwm_gen/Makefile @@ -8,9 +8,9 @@ LIBRARY_NAME := axi_pwm_gen GENERIC_DEPS += ../common/ad_rst.v GENERIC_DEPS += ../common/up_axi.v -GENERIC_DEPS += axi_pwm_gen.v +GENERIC_DEPS += axi_pwm_gen.sv GENERIC_DEPS += axi_pwm_gen_1.v -GENERIC_DEPS += axi_pwm_gen_regmap.v +GENERIC_DEPS += axi_pwm_gen_regmap.sv XILINX_DEPS += ../xilinx/common/ad_rst_constr.xdc XILINX_DEPS += axi_pwm_gen_constr.ttcl diff --git a/library/axi_pwm_gen/axi_pwm_gen.sv b/library/axi_pwm_gen/axi_pwm_gen.sv new file mode 100644 index 00000000000..73284096bec --- /dev/null +++ b/library/axi_pwm_gen/axi_pwm_gen.sv @@ -0,0 +1,394 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright (C) 2021-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: +// +// +// 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_pwm_gen #( + + parameter ID = 0, + parameter ASYNC_CLK_EN = 1, + parameter N_PWMS = 1, + parameter PWM_EXT_SYNC = 0, + parameter EXT_ASYNC_SYNC = 0, + parameter PULSE_0_WIDTH = 7, + parameter PULSE_1_WIDTH = 7, + parameter PULSE_2_WIDTH = 7, + parameter PULSE_3_WIDTH = 7, + parameter PULSE_4_WIDTH = 7, + parameter PULSE_5_WIDTH = 7, + parameter PULSE_6_WIDTH = 7, + parameter PULSE_7_WIDTH = 7, + parameter PULSE_8_WIDTH = 7, + parameter PULSE_9_WIDTH = 7, + parameter PULSE_10_WIDTH = 7, + parameter PULSE_11_WIDTH = 7, + parameter PULSE_12_WIDTH = 7, + parameter PULSE_13_WIDTH = 7, + parameter PULSE_14_WIDTH = 7, + parameter PULSE_15_WIDTH = 7, + parameter PULSE_0_PERIOD = 10, + parameter PULSE_1_PERIOD = 10, + parameter PULSE_2_PERIOD = 10, + parameter PULSE_3_PERIOD = 10, + parameter PULSE_4_PERIOD = 10, + parameter PULSE_5_PERIOD = 10, + parameter PULSE_6_PERIOD = 10, + parameter PULSE_7_PERIOD = 10, + parameter PULSE_8_PERIOD = 10, + parameter PULSE_9_PERIOD = 10, + parameter PULSE_10_PERIOD = 10, + parameter PULSE_11_PERIOD = 10, + parameter PULSE_12_PERIOD = 10, + parameter PULSE_13_PERIOD = 10, + parameter PULSE_14_PERIOD = 10, + parameter PULSE_15_PERIOD = 10, + parameter PULSE_0_OFFSET = 0, + parameter PULSE_1_OFFSET = 0, + parameter PULSE_2_OFFSET = 0, + parameter PULSE_3_OFFSET = 0, + parameter PULSE_4_OFFSET = 0, + parameter PULSE_5_OFFSET = 0, + parameter PULSE_6_OFFSET = 0, + parameter PULSE_7_OFFSET = 0, + parameter PULSE_8_OFFSET = 0, + parameter PULSE_9_OFFSET = 0, + parameter PULSE_10_OFFSET = 0, + parameter PULSE_11_OFFSET = 0, + parameter PULSE_12_OFFSET = 0, + parameter PULSE_13_OFFSET = 0, + parameter PULSE_14_OFFSET = 0, + parameter PULSE_15_OFFSET = 0 +) ( + + // 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, + input ext_sync, + + output pwm_0, + output pwm_1, + output pwm_2, + output pwm_3, + output pwm_4, + output pwm_5, + output pwm_6, + output pwm_7, + output pwm_8, + output pwm_9, + output pwm_10, + output pwm_11, + output pwm_12, + output pwm_13, + output pwm_14, + output pwm_15 +); + + // local parameters + + localparam PWMS = N_PWMS-1; + localparam [31:0] CORE_VERSION = {16'h0002, /* MAJOR */ + 8'h00, /* MINOR */ + 8'h00}; /* PATCH */ + localparam [31:0] CORE_MAGIC = 32'h601a3471; // PLSG + localparam reg [31:0] PULSE_WIDTH_G[15:0] = '{PULSE_0_WIDTH, + PULSE_1_WIDTH, + PULSE_2_WIDTH, + PULSE_3_WIDTH, + PULSE_4_WIDTH, + PULSE_5_WIDTH, + PULSE_6_WIDTH, + PULSE_7_WIDTH, + PULSE_8_WIDTH, + PULSE_9_WIDTH, + PULSE_10_WIDTH, + PULSE_11_WIDTH, + PULSE_12_WIDTH, + PULSE_13_WIDTH, + PULSE_14_WIDTH, + PULSE_15_WIDTH}; + + localparam reg [31:0] PULSE_PERIOD_G[0:15] = '{PULSE_0_PERIOD, + PULSE_1_PERIOD, + PULSE_2_PERIOD, + PULSE_3_PERIOD, + PULSE_4_PERIOD, + PULSE_5_PERIOD, + PULSE_6_PERIOD, + PULSE_7_PERIOD, + PULSE_8_PERIOD, + PULSE_9_PERIOD, + PULSE_10_PERIOD, + PULSE_11_PERIOD, + PULSE_12_PERIOD, + PULSE_13_PERIOD, + PULSE_14_PERIOD, + PULSE_15_PERIOD}; + + localparam reg [31:0] PULSE_OFFSET_G[0:15] = '{PULSE_0_OFFSET, + PULSE_1_OFFSET, + PULSE_2_OFFSET, + PULSE_3_OFFSET, + PULSE_4_OFFSET, + PULSE_5_OFFSET, + PULSE_6_OFFSET, + PULSE_7_OFFSET, + PULSE_8_OFFSET, + PULSE_9_OFFSET, + PULSE_10_OFFSET, + PULSE_11_OFFSET, + PULSE_12_OFFSET, + PULSE_13_OFFSET, + PULSE_14_OFFSET, + PULSE_15_OFFSET}; + + // internal registers + + reg [PWMS:0] sync; + reg [31:0] offset_cnt = 32'd0; + reg offset_alignment = 1'b0; + reg pause_cnt_d = 1'b0; + + // 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 [ 15:0] pwm; + wire [ 31:0] pwm_width_s[0:PWMS]; + wire [ 31:0] pwm_period_s[0:PWMS]; + wire [ 31:0] pwm_offset_s[0:PWMS]; + wire [ 15:0] pwm_armed; + wire load_config_s; + wire pwm_gen_resetn; + wire ext_sync_s; + wire pause_cnt; + + assign up_clk = s_axi_aclk; + assign up_rstn = s_axi_aresetn; + + axi_pwm_gen_regmap #( + .ID (ID), + .ASYNC_CLK_EN (ASYNC_CLK_EN), + .CORE_MAGIC (CORE_MAGIC), + .CORE_VERSION (CORE_VERSION), + .N_PWMS (PWMS), + .PULSE_WIDTH_G (PULSE_WIDTH_G), + .PULSE_PERIOD_G (PULSE_PERIOD_G), + .PULSE_OFFSET_G (PULSE_OFFSET_G) + ) i_regmap ( + .ext_clk (ext_clk), + .clk_out (clk), + .pwm_gen_resetn (pwm_gen_resetn), + .pwm_width (pwm_width_s), + .pwm_period (pwm_period_s), + .pwm_offset (pwm_offset_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)); + + // external sync + + generate + + reg ext_sync_m0 = 1'b1; + reg ext_sync_m1 = 1'b1; + + if (EXT_ASYNC_SYNC) begin + always @(posedge clk) begin + if (pwm_gen_resetn == 1'b0) begin + ext_sync_m0 <= 1'b1; + ext_sync_m1 <= 1'b1; + end else begin + ext_sync_m0 <= (PWM_EXT_SYNC == 1) ? ext_sync : 0; + ext_sync_m1 <= ext_sync_m0; + end + end + assign ext_sync_s = ext_sync_m1; + end else begin + assign ext_sync_s = (PWM_EXT_SYNC == 1) ? ext_sync : 0; + end + + endgenerate + + // offset counter + + always @(posedge clk) begin + if (offset_alignment == 1'b1 || pwm_gen_resetn == 1'b0) begin + offset_cnt <= 32'd0; + end else begin + offset_cnt <= offset_cnt + 1'b1; + end + + if (pwm_gen_resetn == 1'b0) begin + offset_alignment <= 1'b0; + end else begin + // when using external sync an offset alignment can be done only + // after all pwm counters are paused(load_config)/reseated + offset_alignment <= (load_config_s == 1'b1) ? 1'b1 : + offset_alignment & + (ext_sync_s ? 1'b1 : !pause_cnt); + end + end + + assign pause_cnt = ((pwm_armed[1] | + pwm_armed[2] | + pwm_armed[3] | + pwm_armed[4] | + pwm_armed[5] | + pwm_armed[6] | + pwm_armed[7] | + pwm_armed[8] | + pwm_armed[9] | + pwm_armed[10] | + pwm_armed[11] | + pwm_armed[12] | + pwm_armed[13] | + pwm_armed[14] | + pwm_armed[15] ) ? 1'b1 : 1'b0); + genvar i; + generate + for (i = 0; i <= 15; i = i + 1) begin: pwm_cnt + if (i <= PWMS) begin + axi_pwm_gen_1 #( + .PULSE_WIDTH (PULSE_WIDTH_G[i]), + .PULSE_PERIOD (PULSE_PERIOD_G[i]) + ) i_axi_pwm_gen_1 ( + .clk (clk), + .rstn (pwm_gen_resetn), + .pulse_width (pwm_width_s[i]), + .pulse_period (pwm_period_s[i]), + .load_config (load_config_s), + .sync (sync[i]), + .pulse (pwm[i]), + .pulse_armed (pwm_armed[i])); + always @(posedge clk) begin + if (pwm_gen_resetn == 1'b0) begin + sync[i] <= 1'b1; + end else begin + sync[i] <= (offset_cnt == pwm_offset_s[i]) ? 1'b0 : 1'b1; + end + end + end else begin + assign pwm[i] = 1'b0; + assign pwm_armed[i] = 1'b0; + end + end + endgenerate + + assign pwm_0 = pwm[0]; + assign pwm_1 = pwm[1]; + assign pwm_2 = pwm[2]; + assign pwm_3 = pwm[3]; + assign pwm_4 = pwm[4]; + assign pwm_5 = pwm[5]; + assign pwm_6 = pwm[6]; + assign pwm_7 = pwm[7]; + assign pwm_8 = pwm[8]; + assign pwm_9 = pwm[9]; + assign pwm_10 = pwm[10]; + assign pwm_11 = pwm[11]; + assign pwm_12 = pwm[12]; + assign pwm_13 = pwm[13]; + assign pwm_14 = pwm[14]; + assign pwm_15 = pwm[15]; + + 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_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_pwm_gen/axi_pwm_gen.v b/library/axi_pwm_gen/axi_pwm_gen.v deleted file mode 100644 index 14fc60b1429..00000000000 --- a/library/axi_pwm_gen/axi_pwm_gen.v +++ /dev/null @@ -1,356 +0,0 @@ -// *************************************************************************** -// *************************************************************************** -// Copyright (C) 2021-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: -// -// -// 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_pwm_gen #( - - parameter ID = 0, - parameter ASYNC_CLK_EN = 1, - parameter N_PWMS = 1, - parameter PWM_EXT_SYNC = 0, - parameter EXT_ASYNC_SYNC = 0, - parameter PULSE_0_WIDTH = 7, - parameter PULSE_1_WIDTH = 7, - parameter PULSE_2_WIDTH = 7, - parameter PULSE_3_WIDTH = 7, - parameter PULSE_0_PERIOD = 10, - parameter PULSE_1_PERIOD = 10, - parameter PULSE_2_PERIOD = 10, - parameter PULSE_3_PERIOD = 10, - parameter PULSE_0_OFFSET = 0, - parameter PULSE_1_OFFSET = 0, - parameter PULSE_2_OFFSET = 0, - parameter PULSE_3_OFFSET = 0 -) ( - - // 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, - input ext_sync, - - output pwm_0, - output pwm_1, - output pwm_2, - output pwm_3 -); - - // local parameters - - localparam [31:0] CORE_VERSION = {16'h0001, /* MAJOR */ - 8'h00, /* MINOR */ - 8'h00}; /* PATCH */ - localparam [31:0] CORE_MAGIC = 32'h601a3471; // PLSG - - // internal registers - - reg sync_0 = 1'b0; - reg sync_1 = 1'b0; - reg sync_2 = 1'b0; - reg sync_3 = 1'b0; - reg [31:0] offset_cnt = 32'd0; - reg offset_alignment = 1'b0; - reg pause_cnt_d = 1'b0; - - // 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 [127:0] pwm_width_s; - wire [127:0] pwm_period_s; - wire [127:0] pwm_offset_s; - wire [ 31:0] pwm_counter[0:3]; - wire load_config_s; - wire pwm_gen_resetn; - wire ext_sync_s; - wire pause_cnt; - wire offset_alignment_ready; - - assign up_clk = s_axi_aclk; - assign up_rstn = s_axi_aresetn; - - axi_pwm_gen_regmap #( - .ID (ID), - .ASYNC_CLK_EN (ASYNC_CLK_EN), - .CORE_MAGIC (CORE_MAGIC), - .CORE_VERSION (CORE_VERSION), - .N_PWMS (N_PWMS), - .PULSE_0_WIDTH (PULSE_0_WIDTH), - .PULSE_1_WIDTH (PULSE_1_WIDTH), - .PULSE_2_WIDTH (PULSE_2_WIDTH), - .PULSE_3_WIDTH (PULSE_3_WIDTH), - .PULSE_0_PERIOD (PULSE_0_PERIOD), - .PULSE_1_PERIOD (PULSE_1_PERIOD), - .PULSE_2_PERIOD (PULSE_2_PERIOD), - .PULSE_3_PERIOD (PULSE_3_PERIOD), - .PULSE_0_OFFSET (PULSE_0_OFFSET), - .PULSE_1_OFFSET (PULSE_1_OFFSET), - .PULSE_2_OFFSET (PULSE_2_OFFSET), - .PULSE_3_OFFSET (PULSE_3_OFFSET) - ) i_regmap ( - .ext_clk (ext_clk), - .clk_out (clk), - .pwm_gen_resetn (pwm_gen_resetn), - .pwm_width (pwm_width_s), - .pwm_period (pwm_period_s), - .pwm_offset (pwm_offset_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)); - - // external sync - - generate - - reg ext_sync_m0 = 1'b1; - reg ext_sync_m1 = 1'b1; - - if (EXT_ASYNC_SYNC) begin - always @(posedge clk) begin - if (pwm_gen_resetn == 1'b0) begin - ext_sync_m0 <= 1'b1; - ext_sync_m1 <= 1'b1; - end else begin - ext_sync_m0 <= (PWM_EXT_SYNC == 1) ? ext_sync : 0; - ext_sync_m1 <= ext_sync_m0; - end - end - assign ext_sync_s = ext_sync_m1; - end else begin - assign ext_sync_s = (PWM_EXT_SYNC == 1) ? ext_sync : 0; - end - - endgenerate - - // offset counter - - always @(posedge clk) begin - if (offset_alignment == 1'b1 || pwm_gen_resetn == 1'b0) begin - offset_cnt <= 32'd0; - end else begin - offset_cnt <= offset_cnt + 1'b1; - end - - if (pwm_gen_resetn == 1'b0) begin - pause_cnt_d <= 1'b0; - offset_alignment <= 1'b0; - end else begin - pause_cnt_d <= pause_cnt_d; - - // when using external sync an offset alignment can be done only - // after all pwm counters are paused(load_config)/reseated - offset_alignment <= (load_config_s == 1'b1) ? 1'b1 : - offset_alignment & - (ext_sync_s ? 1'b1 : !offset_alignment_ready); - end - end - - assign pause_cnt = ((pwm_counter[0] == 32'd1 || - pwm_counter[1] == 32'd1 || - pwm_counter[2] == 32'd1 || - pwm_counter[3] == 32'd1) ? 1'b1 : 1'b0); - assign offset_alignment_ready = !pause_cnt_d & pause_cnt; - - axi_pwm_gen_1 #( - .PULSE_WIDTH (PULSE_0_WIDTH), - .PULSE_PERIOD (PULSE_0_PERIOD) - ) i0_axi_pwm_gen_1( - .clk (clk), - .rstn (pwm_gen_resetn), - .pulse_width (pwm_width_s[31:0]), - .pulse_period (pwm_period_s[31:0]), - .load_config (load_config_s), - .sync (sync_0), - .pulse (pwm_0), - .pulse_counter (pwm_counter[0])); - - always @(posedge clk) begin - if (pwm_gen_resetn == 1'b0) begin - sync_0 <= 1'b1; - end else begin - sync_0 <= (offset_cnt == pwm_offset_s[31:0]) ? 1'b0 : 1'b1; - end - end - - generate - - if (N_PWMS >= 2) begin - axi_pwm_gen_1 #( - .PULSE_WIDTH (PULSE_1_WIDTH), - .PULSE_PERIOD (PULSE_1_PERIOD) - ) i1_axi_pwm_gen_1( - .clk (clk), - .rstn (pwm_gen_resetn), - .pulse_width (pwm_width_s[63:32]), - .pulse_period (pwm_period_s[63:32]), - .load_config (load_config_s), - .sync (sync_1), - .pulse (pwm_1), - .pulse_counter (pwm_counter[1])); - - always @(posedge clk) begin - if (pwm_gen_resetn == 1'b0) begin - sync_1 <= 1'b1; - end else begin - sync_1 <= (offset_cnt == pwm_offset_s[63:32]) ? 1'b0 : 1'b1; - end - end - end else begin - assign pwm_1 = 1'b0; - assign pwm_counter[1] = 32'd1; - end - - if (N_PWMS >= 3) begin - axi_pwm_gen_1 #( - .PULSE_WIDTH (PULSE_2_WIDTH), - .PULSE_PERIOD (PULSE_2_PERIOD) - ) i2_axi_pwm_gen_1( - .clk (clk), - .rstn (pwm_gen_resetn), - .pulse_width (pwm_width_s[95:64]), - .pulse_period (pwm_period_s[95:64]), - .load_config (load_config_s), - .sync (sync_2), - .pulse (pwm_2), - .pulse_counter (pwm_counter[2])); - - always @(posedge clk) begin - if (pwm_gen_resetn == 1'b0) begin - sync_2 <= 1'b1; - end else begin - sync_2 <= (offset_cnt == pwm_offset_s[95:64]) ? 1'b0 : 1'b1; - end - end - end else begin - assign pwm_2 = 1'b0; - assign pwm_counter[2] = 32'd1; - end - - if (N_PWMS >= 4) begin - axi_pwm_gen_1 #( - .PULSE_WIDTH (PULSE_3_WIDTH), - .PULSE_PERIOD (PULSE_3_PERIOD) - ) i3_axi_pwm_gen_1( - .clk (clk), - .rstn (pwm_gen_resetn), - .pulse_width (pwm_width_s[127:96]), - .pulse_period (pwm_period_s[127:96]), - .load_config (load_config_s), - .sync (sync_3), - .pulse (pwm_3), - .pulse_counter (pwm_counter[3])); - - always @(posedge clk) begin - if (pwm_gen_resetn == 1'b0) begin - sync_3 <= 1'b1; - end else begin - sync_3 <= (offset_cnt == pwm_offset_s[127:96]) ? 1'b0 : 1'b1; - end - end - end else begin - assign pwm_3 = 1'b0; - assign pwm_counter[3] = 32'd1; - end - endgenerate - - 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_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_pwm_gen/axi_pwm_gen_1.v b/library/axi_pwm_gen/axi_pwm_gen_1.v index 0ba775de7d2..c74f2266dbf 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_1.v +++ b/library/axi_pwm_gen/axi_pwm_gen_1.v @@ -48,7 +48,7 @@ module axi_pwm_gen_1 #( input sync, output reg pulse, - output [31:0] pulse_counter + output pulse_armed ); // internal registers @@ -134,6 +134,6 @@ module axi_pwm_gen_1 #( end end - assign pulse_counter = pulse_period_cnt; + assign pulse_armed = phase_align_armed; endmodule diff --git a/library/axi_pwm_gen/axi_pwm_gen_hw.tcl b/library/axi_pwm_gen/axi_pwm_gen_hw.tcl index 42f60146b21..558e2325d29 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_hw.tcl +++ b/library/axi_pwm_gen/axi_pwm_gen_hw.tcl @@ -19,9 +19,9 @@ ad_ip_files axi_pwm_gen [list \ $ad_hdl_dir/library/intel/common/up_rst_constr.sdc \ $ad_hdl_dir/library/util_cdc/util_cdc_constr.tcl \ axi_pwm_gen_constr.sdc \ - axi_pwm_gen_regmap.v \ + axi_pwm_gen_regmap.sv \ axi_pwm_gen_1.v \ - axi_pwm_gen.v] + axi_pwm_gen.sv] # parameters @@ -34,14 +34,50 @@ ad_ip_parameter PULSE_0_WIDTH INTEGER 7 ad_ip_parameter PULSE_1_WIDTH INTEGER 7 ad_ip_parameter PULSE_2_WIDTH INTEGER 7 ad_ip_parameter PULSE_3_WIDTH INTEGER 7 +ad_ip_parameter PULSE_4_WIDTH INTEGER 7 +ad_ip_parameter PULSE_5_WIDTH INTEGER 7 +ad_ip_parameter PULSE_6_WIDTH INTEGER 7 +ad_ip_parameter PULSE_7_WIDTH INTEGER 7 +ad_ip_parameter PULSE_8_WIDTH INTEGER 7 +ad_ip_parameter PULSE_9_WIDTH INTEGER 7 +ad_ip_parameter PULSE_10_WIDTH INTEGER 7 +ad_ip_parameter PULSE_11_WIDTH INTEGER 7 +ad_ip_parameter PULSE_12_WIDTH INTEGER 7 +ad_ip_parameter PULSE_13_WIDTH INTEGER 7 +ad_ip_parameter PULSE_14_WIDTH INTEGER 7 +ad_ip_parameter PULSE_15_WIDTH INTEGER 7 ad_ip_parameter PULSE_0_PERIOD INTEGER 10 ad_ip_parameter PULSE_1_PERIOD INTEGER 10 ad_ip_parameter PULSE_2_PERIOD INTEGER 10 ad_ip_parameter PULSE_3_PERIOD INTEGER 10 +ad_ip_parameter PULSE_4_PERIOD INTEGER 10 +ad_ip_parameter PULSE_5_PERIOD INTEGER 10 +ad_ip_parameter PULSE_6_PERIOD INTEGER 10 +ad_ip_parameter PULSE_7_PERIOD INTEGER 10 +ad_ip_parameter PULSE_8_PERIOD INTEGER 10 +ad_ip_parameter PULSE_9_PERIOD INTEGER 10 +ad_ip_parameter PULSE_10_PERIOD INTEGER 10 +ad_ip_parameter PULSE_11_PERIOD INTEGER 10 +ad_ip_parameter PULSE_12_PERIOD INTEGER 10 +ad_ip_parameter PULSE_13_PERIOD INTEGER 10 +ad_ip_parameter PULSE_14_PERIOD INTEGER 10 +ad_ip_parameter PULSE_15_PERIOD INTEGER 10 ad_ip_parameter PULSE_0_OFFSET INTEGER 0 ad_ip_parameter PULSE_1_OFFSET INTEGER 0 ad_ip_parameter PULSE_2_OFFSET INTEGER 0 ad_ip_parameter PULSE_3_OFFSET INTEGER 0 +ad_ip_parameter PULSE_4_OFFSET INTEGER 0 +ad_ip_parameter PULSE_5_OFFSET INTEGER 0 +ad_ip_parameter PULSE_6_OFFSET INTEGER 0 +ad_ip_parameter PULSE_7_OFFSET INTEGER 0 +ad_ip_parameter PULSE_8_OFFSET INTEGER 0 +ad_ip_parameter PULSE_9_OFFSET INTEGER 0 +ad_ip_parameter PULSE_10_OFFSET INTEGER 0 +ad_ip_parameter PULSE_11_OFFSET INTEGER 0 +ad_ip_parameter PULSE_12_OFFSET INTEGER 0 +ad_ip_parameter PULSE_13_OFFSET INTEGER 0 +ad_ip_parameter PULSE_14_OFFSET INTEGER 0 +ad_ip_parameter PULSE_15_OFFSET INTEGER 0 # interfaces @@ -53,6 +89,6 @@ ad_interface clock ext_clk input 1 ad_interface signal ext_sync input 1 # output signals -for {set i 0} {$i < 4} {incr i} { +for {set i 0} {$i < 16} {incr i} { ad_interface signal pwm_$i output 1 if_pwm } diff --git a/library/axi_pwm_gen/axi_pwm_gen_ip.tcl b/library/axi_pwm_gen/axi_pwm_gen_ip.tcl index 3a69c1d6926..7dd8643593d 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_ip.tcl +++ b/library/axi_pwm_gen/axi_pwm_gen_ip.tcl @@ -15,9 +15,9 @@ adi_ip_files axi_pwm_gen [list \ "$ad_hdl_dir/library/common/up_axi.v" \ "$ad_hdl_dir/library/xilinx/common/ad_rst_constr.xdc" \ "axi_pwm_gen_constr.ttcl" \ - "axi_pwm_gen_regmap.v" \ + "axi_pwm_gen_regmap.sv" \ "axi_pwm_gen_1.v" \ - "axi_pwm_gen.v"] + "axi_pwm_gen.sv"] adi_ip_properties axi_pwm_gen adi_ip_ttcl axi_pwm_gen "axi_pwm_gen_constr.ttcl" @@ -100,8 +100,8 @@ set_property -dict [list \ "widget" "checkBox" \ ] [ipgui::get_guiparamspec -name "EXT_ASYNC_SYNC" -component $cc] -# Maximum 4 pwms -for {set i 0} {$i < 4} {incr i} { +# Maximum 16 pwms +for {set i 0} {$i < 16} {incr i} { ipgui::add_param -name "PULSE_${i}_WIDTH" -component $cc -parent $page0 set_property -dict [list \ "display_name" "PULSE $i width" \ @@ -142,7 +142,7 @@ for {set i 0} {$i < 4} {incr i} { [ipx::get_user_parameters PULSE_${i}_OFFSET -of_objects $cc] } -for {set i 1} {$i < 4} {incr i} { +for {set i 0} {$i < 16} {incr i} { adi_set_ports_dependency "pwm_$i" \ "(spirit:decode(id('MODELPARAM_VALUE.N_PWMS')) > $i)" } diff --git a/library/axi_pwm_gen/axi_pwm_gen_regmap.sv b/library/axi_pwm_gen/axi_pwm_gen_regmap.sv new file mode 100644 index 00000000000..91a70304c36 --- /dev/null +++ b/library/axi_pwm_gen/axi_pwm_gen_regmap.sv @@ -0,0 +1,202 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright (C) 2021-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: +// +// +// 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_pwm_gen_regmap #( + + parameter ID = 0, + parameter CORE_MAGIC = 0, + parameter CORE_VERSION = 0, + parameter ASYNC_CLK_EN = 1, + parameter N_PWMS = 0, + parameter reg [31:0] PULSE_WIDTH_G[0:15] = '{16{32'd0}}, + parameter reg [31:0] PULSE_PERIOD_G[0:15] = '{16{32'd0}}, + parameter reg [31:0] PULSE_OFFSET_G[0:15] = '{16{32'd0}} +) ( + + // external clock + + input ext_clk, + + // control and status signals + + output clk_out, + output pwm_gen_resetn, + output [31:0] pwm_width[0:N_PWMS], + output [31:0] pwm_period[0:N_PWMS], + output [31:0] pwm_offset[0:N_PWMS], + 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_pwm_width[0:N_PWMS] = PULSE_WIDTH_G[0:N_PWMS]; + reg [31:0] up_pwm_period[0:N_PWMS] = PULSE_PERIOD_G[0:N_PWMS]; + reg [31:0] up_pwm_offset[0:N_PWMS] = PULSE_OFFSET_G[0:N_PWMS]; + reg up_load_config = 1'b0; + reg up_reset = 1'b1; + + genvar n; + + always @(posedge up_clk) begin + if (up_rstn == 0) begin + up_wack <= 'd0; + up_scratch <= 'd0; + up_pwm_width = PULSE_WIDTH_G[0:N_PWMS]; + up_pwm_period = PULSE_PERIOD_G[0:N_PWMS]; + up_pwm_offset = PULSE_OFFSET_G[0:N_PWMS]; + up_load_config <= 1'b0; + up_reset <= 1'b1; + end else begin + up_wack <= up_wreq; + if ((up_wreq == 1'b1) && (up_waddr == 14'h2)) begin + up_scratch <= up_wdata; + end + if ((up_wreq == 1'b1) && (up_waddr == 14'h4)) begin + up_reset <= up_wdata[0]; + up_load_config <= up_wdata[1]; + end else begin + up_load_config <= 1'b0; + end + for (int i = 0; i <= N_PWMS; i++) begin + if ((up_wreq == 1'b1) && (up_waddr == 14'h10 + i)) begin + up_pwm_period[i] <= up_wdata; + end + if ((up_wreq == 1'b1) && (up_waddr == 14'h20 + i)) begin + up_pwm_width[i] <= up_wdata; + end + if ((up_wreq == 1'b1) && (up_waddr == 14'h30 + i)) begin + up_pwm_offset[i] <= up_wdata; + end + 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 + if (up_raddr[13:4] == 10'd0) begin + case (up_raddr) + 14'h0: up_rdata <= CORE_VERSION; + 14'h1: up_rdata <= ID; + 14'h2: up_rdata <= up_scratch; + 14'h3: up_rdata <= CORE_MAGIC; + 14'h4: up_rdata <= up_reset; + 14'h5: up_rdata <= N_PWMS +1; + default: up_rdata <= 0; + endcase + end else if (up_raddr[3:0] > N_PWMS) begin + up_rdata <= 32'b0; + end else if (up_raddr[13:4] == 10'd1) begin + up_rdata <= up_pwm_period[up_raddr[3:0]]; + end else if (up_raddr[13:4] == 10'd2) begin + up_rdata <= up_pwm_width[up_raddr[3:0]]; + end else if (up_raddr[13:4] == 10'd3) begin + up_rdata <= up_pwm_offset[up_raddr[3:0]]; + end + end else begin + up_rdata <= 32'd0; + end + end + end + + generate + if (ASYNC_CLK_EN) begin : counter_external_clock + + assign clk_out = ext_clk; + + ad_rst i_d_rst_reg ( + .rst_async (up_reset), + .clk (clk_out), + .rstn (pwm_gen_resetn), + .rst ()); + + for (n = 0; n <= N_PWMS; n = n + 1) begin: up_to_adc_cdc + sync_data #( + .NUM_OF_BITS (96), + .ASYNC_CLK (1)) + i_pwm_props ( + .in_clk (up_clk), + .in_data ({up_pwm_period[n], + up_pwm_width[n], + up_pwm_offset[n]}), + .out_clk (clk_out), + .out_data ({pwm_period[n], + pwm_width[n], + pwm_offset[n]})); + end + + 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), + .out_event (load_config)); + + end else begin : counter_sys_clock // counter is running on system clk + + assign clk_out = up_clk; + assign pwm_gen_resetn = ~up_reset; + for (n = 0; n <= N_PWMS; n = n + 1) begin: up_cd + assign pwm_period[n] = up_pwm_period[n]; + assign pwm_width[n] = up_pwm_width[n]; + assign pwm_offset[n] = up_pwm_offset[n]; + end + assign load_config = up_load_config; + + end + endgenerate + +endmodule diff --git a/library/axi_pwm_gen/axi_pwm_gen_regmap.v b/library/axi_pwm_gen/axi_pwm_gen_regmap.v deleted file mode 100644 index 0d81d0664cb..00000000000 --- a/library/axi_pwm_gen/axi_pwm_gen_regmap.v +++ /dev/null @@ -1,274 +0,0 @@ -// *************************************************************************** -// *************************************************************************** -// Copyright (C) 2021-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: -// -// -// 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_pwm_gen_regmap #( - - parameter ID = 0, - parameter CORE_MAGIC = 0, - parameter CORE_VERSION = 0, - parameter ASYNC_CLK_EN = 1, - parameter N_PWMS = 3, - parameter PULSE_0_WIDTH = 7, - parameter PULSE_1_WIDTH = 7, - parameter PULSE_2_WIDTH = 7, - parameter PULSE_3_WIDTH = 7, - parameter PULSE_0_PERIOD = 10, - parameter PULSE_1_PERIOD = 10, - parameter PULSE_2_PERIOD = 10, - parameter PULSE_3_PERIOD = 10, - parameter PULSE_0_EXT_SYNC = 0, - parameter PULSE_0_OFFSET = 0, - parameter PULSE_1_OFFSET = 0, - parameter PULSE_2_OFFSET = 0, - parameter PULSE_3_OFFSET = 0 -) ( - - // external clock - - input ext_clk, - - // control and status signals - - output clk_out, - output pwm_gen_resetn, - output [127:0] pwm_width, - output [127:0] pwm_period, - output [127:0] pwm_offset, - 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_pwm_width_0 = PULSE_0_WIDTH; - reg [31:0] up_pwm_width_1 = PULSE_1_WIDTH; - reg [31:0] up_pwm_width_2 = PULSE_2_WIDTH; - reg [31:0] up_pwm_width_3 = PULSE_3_WIDTH; - reg [31:0] up_pwm_period_0 = PULSE_0_PERIOD; - reg [31:0] up_pwm_period_1 = PULSE_1_PERIOD; - reg [31:0] up_pwm_period_2 = PULSE_2_PERIOD; - reg [31:0] up_pwm_period_3 = PULSE_3_PERIOD; - reg [31:0] up_pwm_offset_0 = PULSE_0_OFFSET; - reg [31:0] up_pwm_offset_1 = PULSE_1_OFFSET; - reg [31:0] up_pwm_offset_2 = PULSE_2_OFFSET; - reg [31:0] up_pwm_offset_3 = PULSE_3_OFFSET; - reg up_load_config = 1'b0; - reg up_reset = 1'b1; - - always @(posedge up_clk) begin - if (up_rstn == 0) begin - up_wack <= 'd0; - up_scratch <= 'd0; - up_pwm_width_0 <= PULSE_0_WIDTH; - up_pwm_width_1 <= PULSE_1_WIDTH; - up_pwm_width_2 <= PULSE_2_WIDTH; - up_pwm_width_3 <= PULSE_3_WIDTH; - up_pwm_period_0 <= PULSE_0_PERIOD; - up_pwm_period_1 <= PULSE_1_PERIOD; - up_pwm_period_2 <= PULSE_2_PERIOD; - up_pwm_period_3 <= PULSE_3_PERIOD; - up_pwm_offset_0 <= PULSE_0_OFFSET; - up_pwm_offset_1 <= PULSE_1_OFFSET; - up_pwm_offset_2 <= PULSE_2_OFFSET; - up_pwm_offset_3 <= PULSE_3_OFFSET; - up_load_config <= 1'b0; - up_reset <= 1'b1; - end else begin - up_wack <= up_wreq; - if ((up_wreq == 1'b1) && (up_waddr == 14'h2)) begin - up_scratch <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'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 == 14'h10)) begin - up_pwm_period_0 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h11)) begin - up_pwm_width_0 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h12)) begin - up_pwm_offset_0 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h13)) begin - up_pwm_period_1 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h14)) begin - up_pwm_width_1 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h15)) begin - up_pwm_offset_1 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h16)) begin - up_pwm_period_2 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h17)) begin - up_pwm_width_2 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h18)) begin - up_pwm_offset_2 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h19)) begin - up_pwm_period_3 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h1a)) begin - up_pwm_width_3 <= up_wdata; - end - if ((up_wreq == 1'b1) && (up_waddr == 14'h1b)) begin - up_pwm_offset_3 <= 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) - 14'h0: up_rdata <= CORE_VERSION; - 14'h1: up_rdata <= ID; - 14'h2: up_rdata <= up_scratch; - 14'h3: up_rdata <= CORE_MAGIC; - 14'h4: up_rdata <= up_reset; - 14'h5: up_rdata <= N_PWMS; - 14'h10: up_rdata <= up_pwm_period_0; - 14'h11: up_rdata <= up_pwm_width_0; - 14'h12: up_rdata <= up_pwm_offset_0; - 14'h13: up_rdata <= up_pwm_period_1; - 14'h14: up_rdata <= up_pwm_width_1; - 14'h15: up_rdata <= up_pwm_offset_1; - 14'h16: up_rdata <= up_pwm_period_2; - 14'h17: up_rdata <= up_pwm_width_2; - 14'h18: up_rdata <= up_pwm_offset_2; - 14'h19: up_rdata <= up_pwm_period_3; - 14'h1a: up_rdata <= up_pwm_width_3; - 14'h1b: up_rdata <= up_pwm_offset_3; - 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_out = ext_clk; - - ad_rst i_d_rst_reg ( - .rst_async (up_reset), - .clk (clk_out), - .rstn (pwm_gen_resetn), - .rst ()); - - sync_data #( - .NUM_OF_BITS (128), - .ASYNC_CLK (1) - ) i_pwm_period_sync ( - .in_clk (up_clk), - .in_data ({up_pwm_period_3, - up_pwm_period_2, - up_pwm_period_1, - up_pwm_period_0}), - .out_clk (clk_out), - .out_data (pwm_period)); - - sync_data #( - .NUM_OF_BITS (128), - .ASYNC_CLK (1) - ) i_pwm_width_sync ( - .in_clk (up_clk), - .in_data ({up_pwm_width_3, - up_pwm_width_2, - up_pwm_width_1, - up_pwm_width_0}), - .out_clk (clk_out), - .out_data (pwm_width)); - - sync_data #( - .NUM_OF_BITS (128), - .ASYNC_CLK (1) - ) i_pwm_offset_sync ( - .in_clk (up_clk), - .in_data ({up_pwm_offset_3, - up_pwm_offset_2, - up_pwm_offset_1, - up_pwm_offset_0}), - .out_clk (clk_out), - .out_data (pwm_offset)); - - 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), - .out_event (load_config)); - - end else begin : counter_sys_clock // counter is running on system clk - - assign clk_out = up_clk; - assign pwm_gen_resetn = ~up_reset; - assign pwm_period = {up_pwm_period_3, up_pwm_period_2, up_pwm_period_1, up_pwm_period_0}; - assign pwm_width = {up_pwm_width_3, up_pwm_width_2, up_pwm_width_1, up_pwm_width_0}; - assign pwm_offset = {up_pwm_offset_3, up_pwm_offset_2, up_pwm_offset_1, up_pwm_offset_0}; - assign load_config = up_load_config; - - end - endgenerate - -endmodule From 6048f01a98cd9d9b69c0de71cb8bca20e6442128 Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Thu, 23 Nov 2023 19:32:09 +0200 Subject: [PATCH 2/4] axi_pwm_gen: Offset mecanism fix When leaving the offset equal to zero for a pwm channel. That pwm channel was not waiting for all channels to get in sync after a load config. Signed-off-by: AndreiGrozav --- library/axi_pwm_gen/axi_pwm_gen.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/axi_pwm_gen/axi_pwm_gen.sv b/library/axi_pwm_gen/axi_pwm_gen.sv index 73284096bec..929dfeb14ab 100644 --- a/library/axi_pwm_gen/axi_pwm_gen.sv +++ b/library/axi_pwm_gen/axi_pwm_gen.sv @@ -333,7 +333,7 @@ module axi_pwm_gen #( if (pwm_gen_resetn == 1'b0) begin sync[i] <= 1'b1; end else begin - sync[i] <= (offset_cnt == pwm_offset_s[i]) ? 1'b0 : 1'b1; + sync[i] <= (offset_cnt == pwm_offset_s[i]) ? offset_alignment : 1'b1; end end end else begin From be18f665036c3f2bb599f28aca30a51136b654a5 Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Thu, 23 Nov 2023 19:44:21 +0200 Subject: [PATCH 3/4] axi_pwm_gen: Start, Stop fix Previously when issuing a load_config, each pwm channel was stopped in its tracks and waited for an external sync, if that was active, or load_config release. The desired behaviour is to wait for the pwm channels to finish their events from the current period, before a new aligned start. Also, the first positive edge of each pulse was initiated only in the second pwm channel period. This niche behaviours have not affected any functionality in the long term alignments for current setups. Signed-off-by: AndreiGrozav --- library/axi_pwm_gen/axi_pwm_gen_1.v | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/library/axi_pwm_gen/axi_pwm_gen_1.v b/library/axi_pwm_gen/axi_pwm_gen_1.v index c74f2266dbf..8e26215fc57 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_1.v +++ b/library/axi_pwm_gen/axi_pwm_gen_1.v @@ -47,7 +47,7 @@ module axi_pwm_gen_1 #( input load_config, input sync, - output reg pulse, + output pulse, output pulse_armed ); @@ -59,6 +59,8 @@ module axi_pwm_gen_1 #( reg [31:0] pulse_period_d = PULSE_PERIOD; reg [31:0] pulse_width_d = PULSE_WIDTH; reg phase_align_armed = 1'b1; + reg pulse_i = 1'b0; + reg busy = 1'b0; // internal wires @@ -107,7 +109,19 @@ module axi_pwm_gen_1 #( end end - assign phase_align = phase_align_armed & sync; + always @(posedge clk) begin + if (rstn == 1'b0) begin + busy <= 1'b0; + end else begin + if (end_of_period) begin + busy <= 1'b0; + end else if ( ~(phase_align_armed & sync)) begin + busy <= 1'b1; + end + end + end + + assign phase_align = phase_align_armed & sync & busy; // a free running counter @@ -127,13 +141,14 @@ module axi_pwm_gen_1 #( // generate pulse with a specified width always @ (posedge clk) begin - if ((rstn == 1'b0) || (phase_align == 1'b1) || (end_of_pulse == 1'b1)) begin - pulse <= 1'b0; - end else if (end_of_period == 1'b1 && pulse_enable == 1'b1) begin - pulse <= 1'b1; + if ((rstn == 1'b0) || (end_of_pulse == 1'b1)) begin + pulse_i <= 1'b0; + end else if ((end_of_period == 1'b1 || phase_align == 1'b1) && pulse_enable == 1'b1) begin + pulse_i <= 1'b1; end end + assign pulse = pulse_i & !(phase_align_armed & sync); assign pulse_armed = phase_align_armed; endmodule From ef3207a3404e18a4a2b5f6af9c785393891fa50d Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Fri, 24 Nov 2023 14:09:02 +0200 Subject: [PATCH 4/4] axi_pwm_gen: Update ttcl constraints Signed-off-by: AndreiGrozav --- library/axi_pwm_gen/axi_pwm_gen_constr.ttcl | 32 ++++----------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/library/axi_pwm_gen/axi_pwm_gen_constr.ttcl b/library/axi_pwm_gen/axi_pwm_gen_constr.ttcl index d7534732708..91c96e4f08f 100644 --- a/library/axi_pwm_gen/axi_pwm_gen_constr.ttcl +++ b/library/axi_pwm_gen/axi_pwm_gen_constr.ttcl @@ -17,35 +17,15 @@ set_property ASYNC_REG TRUE \ [get_cells -hier {*cdc_sync_stage1_reg*}] \ [get_cells -hier {*cdc_sync_stage2_reg*}] - set_false_path -from [get_cells -hierarchical * -filter {NAME=~*i_pwm_period_sync/cdc_hold_reg*}] \ - -to [get_cells -hierarchical * -filter {NAME=~*i_pwm_period_sync/out_data_reg*}] \ - - set_false_path -from [get_cells -hierarchical * -filter {NAME=~*i_pwm_width_sync/cdc_hold_reg*}] \ - -to [get_cells -hierarchical * -filter {NAME=~*i_pwm_width_sync/out_data_reg*}] \ - - set_false_path -from [get_cells -hierarchical * -filter {NAME=~*i_pwm_offset_sync/cdc_hold_reg*}] \ - -to [get_cells -hierarchical * -filter {NAME=~*i_pwm_offset_sync/out_data_reg*}] \ - - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_period_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_period_sync/i_sync_in/cdc_sync_stage1_reg[0]/D}] - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_period_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_period_sync/i_sync_out/cdc_sync_stage1_reg[0]/D}] - - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_width_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_width_sync/i_sync_in/cdc_sync_stage1_reg[0]/D}] - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_width_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_width_sync/i_sync_out/cdc_sync_stage1_reg[0]/D}] + set_false_path -from [get_cells -hierarchical * -filter {NAME=~*i_pwm_props/cdc_hold_reg*}] \ + -to [get_cells -hierarchical * -filter {NAME=~*i_pwm_props/out_data_reg*}] \ set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_offset_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_offset_sync/i_sync_in/cdc_sync_stage1_reg[0]/D}] + -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_props/out_toggle_d1_reg/C}] \ + -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_props/i_sync_in/cdc_sync_stage1_reg[0]/D}] set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_offset_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_offset_sync/i_sync_out/cdc_sync_stage1_reg[0]/D}] + -from [get_pins -hierarchical * -filter {NAME=~*i_pwm_props/in_toggle_d1_reg/C}] \ + -to [get_pins -hierarchical * -filter {NAME=~*i_pwm_props/i_sync_out/cdc_sync_stage1_reg[0]/D}] set_false_path \ -from [get_pins -hierarchical * -filter {NAME=~*i_load_config_sync/out_toggle_d1_reg/C}] \