From c3ae609bc87925715a8c0bb804e6b51b95e0a760 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Thu, 24 Feb 2022 13:44:05 +0200 Subject: [PATCH] data_offload: Refactor core Deprecate unused parameters. Change to MEM_SIZE_LOG2, to support only power of 2 storage sizes for now. However in the future we might want to add support for non pow2 sizes so register map is not changed. Change transfer length to -1 value to spare logic. Change FIFO interface to AXIS to have backpressure, this allows the implementation of data movement logic in the storage unit and let the FSM handle high level control an synchronization and control the storage unit through a control interface. Refactor FSM to have preparation states where slow storages can be configured and started ahead of the data handling. Make bypasss FIFO optional since in some cases causes timing failures due the missing output register of the memory. This can be targeted in a later commit. Hook up underflow/overflow to regmap useful in case of external memory where rate drops due misconfiguration can be detected. Cleanup for verilator. Scripting: Add HBM and DDR external memory support using util_hbm IP Replace asym_block_ram with util_do_ram IP --- library/data_offload/Makefile | 5 + library/data_offload/README.md | 93 +-- library/data_offload/data_offload.v | 265 ++++---- library/data_offload/data_offload_constr.ttcl | 112 ++-- library/data_offload/data_offload_fsm.v | 607 +++++------------- library/data_offload/data_offload_ip.tcl | 178 +++-- library/data_offload/data_offload_regmap.v | 146 +++-- library/data_offload/data_offload_sv.ttcl | 18 +- library/data_offload/docs/generic_bd.svg | 54 +- projects/common/xilinx/data_offload_bd.tcl | 98 ++- 10 files changed, 631 insertions(+), 945 deletions(-) diff --git a/library/data_offload/Makefile b/library/data_offload/Makefile index d608b7661..25843b379 100644 --- a/library/data_offload/Makefile +++ b/library/data_offload/Makefile @@ -16,7 +16,12 @@ GENERIC_DEPS += data_offload_regmap.v XILINX_DEPS += data_offload_ip.tcl XILINX_DEPS += data_offload_sv.ttcl +XILINX_DEPS += ../interfaces/if_do_ctrl.xml +XILINX_DEPS += ../interfaces/if_do_ctrl_rtl.xml + XILINX_LIB_DEPS += util_axis_fifo_asym XILINX_LIB_DEPS += util_cdc +XILINX_INTERFACE_DEPS += interfaces + include ../scripts/library.mk diff --git a/library/data_offload/README.md b/library/data_offload/README.md index 239de51e0..1e7e77d4c 100644 --- a/library/data_offload/README.md +++ b/library/data_offload/README.md @@ -59,17 +59,14 @@ URAM, external memory etc.) |----------------------|:-----------:|:----------:|:---------------------------:| |ID | integer | 0 | Instance ID number | |MEM_TYPE | [ 0:0] | 0 | Define the used storage type: FPGA RAM - 0; external DDR - 1 | -|MEM_SIZE | [31:0] | 1024 | Define the size of the storage element | -|MEMC_UIF_DATA_WIDTH | [ 0:0] | 512 | The valid data depends on the DDRx memory controller IP. | +|MEM_SIZE_LOG2 | integer | 10 | Log2 value of storage size, defines the width of transfer length control signals. | |TX_OR_RXN_PATH | [ 0:0] | 1 | If set TX path enabled, otherwise RX | |SRC_DATA_WIDTH | integer | 64 | The data width of the source interface | -|SRC_RAW_DATA_EN | [ 0:0] | 0 | Enable if the data path does extend samples to 16 bits | -|SRC_ADDR_WIDTH | integer | 8 | The address width of the source interface, should be defined relative to the MEM_SIZE (MEM_SIZE/SRC_DATA_WIDTH/8) | -|DST_ADDR_WIDTH | integer | 7 | The address width of the source interface, should be defined relative to the MEM_SIZE (MEM_SIZE/DST_DATA_WIDTH/8) | -|DST_DATA_WIDTH | integer | 64 | The data width of the destination interface | -|DST_RAW_DATA_EN | [ 0:0] | 0 | Enable if the data path does extend samples to 16 bits | +|DST_DATA_WIDTH | integer | 124 | The data width of the destination interface | |DST_CYCLIC_EN | [ 0:0] | 0 | Enables CYCLIC mode for destinations like DAC | -|AUTO_BRINUP | [ 0:0] | 0 | If enabled the IP runs automatically after bootup | +|AUTO_BRINGUP | [ 0:0] | 1 | If enabled the IP runs automatically after bootup | +|SYNC_EXT_ADD_INTERNAL_CDC | [ 0:0] | 1 | If enabled the external sync pin is synchronized to the internal clock domain with a CDC. | +|HAS_BYPASS | [ 0:0] | 1 | If set to zero the bypass FIFO is not implemented. | ## Interfaces @@ -141,9 +138,9 @@ input s_axi_rready **NOTE**: To simplify the design both the source and destination data interface is an AXI4 streaming interface. A FIFO write (ADC) interface can be treated as AXI4 -stream where only the master controles the data rate (s_axis_ready is always asserted), +stream where only the master controls the data rate (s_axis_ready is always asserted), and a FIFO read (DAC) interface can be treated as an AXI4 stream where only the slave -controles the data rate. (m_axis_valid is always asserted). +controls the data rate. (m_axis_valid is always asserted). #### AXI4 Stream interface (S_AXIS | M_AXIS) @@ -178,76 +175,23 @@ and **axis_tkeep** will be used to indicate a partial last beat. This informatio should be transferred from the source domain to the sink domain, so we can read back the data from memory correctly. -#### FIFO source and destination interface to the storage unit +#### AXIS source and destination interface to the storage unit -This is non-blocking (no back-pressure) interface for the storage unit, -having an address bus too, so an ad_mem module can be connected directly to controller IP. - -```verilog -// This is a FIFO source interface - it's clocked on the source clock (s_axis_aclk) -// Reset signal -output fifo_src_resetn -// write enable signal -output fifo_src_wen -// address bus for internal memory -output [SRC_ADDR_WIDTH-1:0] fifo_src_waddr -// source data bus -output [SRC_DATA_WIDTH-1:0] fifo_src_wdata -// write last, indicates the last valid transfer -output fifo_src_wlast -``` - -```verilog -// This is a FIFO destination interface - it's clocked on the destination clock (m_axis_aclk) -// Reset signal -output fifo_dst_resetn -// read enable signal -output fifo_dst_ren -// indicate if the storage is ready to accept read requests -output fifo_dst_ready, -// address bus for internal memory -output [DST_ADDR_WIDTH-1:0] fifo_dst_raddr -// destination data bus -output [DST_DATA_WIDTH-1:0] fifo_dst_rdata -``` - -```verilog -// This is a Slave FIFO Read interface -// device digital interface clock, or core clock -input fifo_rd_clk -// enables the channel -- in our case this is redundant -- maybe we do neet to use it at all -input fifo_rd_enable -// validates the data on the bus, it's driven by the device indicates when the core latches the data -input fifo_rd_valid -// primary payload, its data width is equal with the channel's data width -output [DATA_WIDTH-1:0] fifo_rd_data -// indicates an underflow, the source (offload FIFO in this case) can not produce the data fast enough -output fifo_rd_unf -``` +This is blocking (back-pressure) interface for the storage unit, +with similar behavior of main AXIS data interfaces. ### Initialization request interface -Define a simple request/acknowledge interface to initialize the memory: +Define a simple request interface to initialize the memory: * The request will comes from the system and will put the data offload FSM into a standby/ready state. - * Both RX and TX path should have a separate initialization request interface. - * Acknowledge will be asserted by the data offload IP as the FSM is ready to -receive data. (from TX_DMA or ADC) - * In case of ADC: after the acknowledge samples will be stored into the memory -using one of the SYNC modes. - - * In case of the DAC: after acknowledge data from the DMA will be stored into -the memory. Acknowledge will stay asserted until one of the SYNC mode is used, -after that the source interface of the IP will stay in busy state. (all the DMA -transfers will be blocked) #### Synchronization modes * **AUTOMATIC** - * ADC: As the acknowledge of the initialization interface is asserted, the -IP will start to fill up the buffer with samples. + * ADC: The IP will start to fill up the buffer with samples as soon as possible. * DAC: As the DMA will send a valid last, the FSM will start to send the stored data to the device. @@ -274,13 +218,14 @@ into or from the memory. | 0x0002 | 0x0008 | | `SCRATCH` | RW | SYS | Scratch register | | 0x0003 | 0x000C | | `IDENTIFICATION` | RO | SYS | Peripheral identification. Default value: 0x44414F46 - ('D','A','O','F') | | 0x0004 | 0x0010 | | `SYNTHESIS_CONFIG` | RO | SYS | Core configuration registers | +| | | [13: 8] | `MEM_SIZE_LOG2` | | | Log2 of memory size in bytes | +| | | [ 2: 2] | `HAS_BYPASS` | | | If not set the bypass logic is not implemented. | | | | [ 1: 1] | `TX_OR_RXN_PATH` | | | RX Path => 0, TX => 1 | | | | [ 0: 0] | `MEMORY_TYPE` | | | The used storage type (embedded => 0 or external => 1) | -| 0x0005 | 0x0014 | | `MEMORY_SIZE_LSB` | RO | SYS | 32bits LSB of the memory size register | -| 0x0006 | 0x0018 | | `MEMORY_SIZE_MSB` | RO | SYS | 2bits MSB of the memory size register | -| | | [ 1: 0] | `MEMORY_SIZE_MSB` | | | | | 0x0007 | 0x001C | | `TRANSFER_LENGTH` | RW | SRC | Transfer length | | 0x0020 | 0x0080 | | `MEM_PHY_STATE` | RO | DDR | Status bits of the memory controller IP | +| | | [ 5: 5] | `UNDERFLOW` | RW1C | | Indicates that storage could not handle data rate during play. Available when core is in TX mode.| +| | | [ 4: 4] | `OVERFLOW` | RW1C | | Indicates that storage could not handle data rate during capture. Available when core is in RX mode. | | | | [ 0: 0] | `CALIB_COMPLETE` | | | Indicates that the memory initialization and calibration have completed successfully | | 0x0021 | 0x0084 | | `RESETN_OFFLOAD` | RW | DST/SRC | Reset all the internal address registers and state machines | | | | [ 0: 0] | `RESETN` | | | | @@ -292,10 +237,8 @@ into or from the memory. | 0x0041 | 0x0104 | | `SYNC_CONFIG` | RW | SRC | Synchronization setup | | | | [ 1: 0] | `SYNC_CONFIG` | | | Auto - '0'; hardware - '1'; software - '2' | | 0x0080 | 0x0200 | | `FSM_DBG` | RO | | Debug register for the offload FSM | -| | | [ 5: 4] | `FSM_STATE_READ` | | SRC | The current state of the read-offload state machine | -| | | [ 1: 0] | `FSM_STATE_WRITE` | | DST | The current state of the write-offload state machine | -| 0x0081 | 0x0204 | | `SAMPLE_COUNT_LSB` | RO | SRC | Stored sample count (32 LSB) | -| 0x0082 | 0x0208 | | `SAMPLE_COUNT_MSB` | RO | SRC | Stored sample count (32 MSB) | +| | | [11: 8] | `FSM_STATE_READ` | | SRC | The current state of the read-offload state machine | +| | | [ 4: 0] | `FSM_STATE_WRITE` | | DST | The current state of the write-offload state machine | ## Clock tree diff --git a/library/data_offload/data_offload.v b/library/data_offload/data_offload.v index 01d3816c5..2e12b88cf 100644 --- a/library/data_offload/data_offload.v +++ b/library/data_offload/data_offload.v @@ -38,25 +38,19 @@ module data_offload #( parameter ID = 0, parameter [ 0:0] MEM_TYPE = 1'b0, // 1'b0 -FPGA RAM; 1'b1 - external memory - parameter [33:0] MEM_SIZE = 1024, // memory size in bytes -1 - max 16 GB - parameter MEMC_UIF_DATA_WIDTH = 512, - parameter MEMC_UIF_ADDRESS_WIDTH = 31, - parameter [31:0] MEMC_BADDRESS = 32'h00000000, + parameter MEM_SIZE_LOG2 = 10, // log2 of memory size in bytes parameter TX_OR_RXN_PATH = 0, // if set IP is used in TX path, other wise in RX path parameter SRC_DATA_WIDTH = 64, - parameter SRC_RAW_DATA_EN = 1'b0, - - parameter SRC_ADDR_WIDTH = 8, - parameter DST_ADDR_WIDTH = 7, parameter DST_DATA_WIDTH = 128, - parameter DST_RAW_DATA_EN = 1'b0, // TBD parameter DST_CYCLIC_EN = 1'b0, // 1'b1 - CYCLIC mode enabled; 1'b0 - CYCLIC mode disabled parameter AUTO_BRINGUP = 1, - parameter SYNC_EXT_ADD_INTERNAL_CDC = 1) ( + parameter SYNC_EXT_ADD_INTERNAL_CDC = 1, + parameter HAS_BYPASS = 1 +) ( // AXI4 Slave for configuration @@ -86,6 +80,7 @@ module data_offload #( input s_axis_aclk, input s_axis_aresetn, + output s_axis_ready, input s_axis_valid, input [SRC_DATA_WIDTH-1:0] s_axis_data, @@ -97,6 +92,7 @@ module data_offload #( input m_axis_aclk, input m_axis_aresetn, + input m_axis_ready, output m_axis_valid, output [DST_DATA_WIDTH-1:0] m_axis_data, @@ -106,23 +102,43 @@ module data_offload #( // initialization request interface input init_req, - output init_ack, input sync_ext, - // FIFO interface - Memory UI + // AXIS - Memory UI to storage - output fifo_src_wen, - output fifo_src_resetn, - output [SRC_ADDR_WIDTH-1:0] fifo_src_waddr, - output [SRC_DATA_WIDTH-1:0] fifo_src_wdata, - output fifo_src_wlast, + // AXI stream master for source stream to storage (BRAM/URAM/DDR/HBM) + // runs on s_axis_aclk and s_axis_aresetn + input m_storage_axis_ready, + output m_storage_axis_valid, + output [SRC_DATA_WIDTH-1:0] m_storage_axis_data, + output m_storage_axis_last, + output [SRC_DATA_WIDTH/8-1:0] m_storage_axis_tkeep, - output fifo_dst_ren, - input fifo_dst_ready, - output fifo_dst_resetn, - output [DST_ADDR_WIDTH-1:0] fifo_dst_raddr, - input [DST_DATA_WIDTH-1:0] fifo_dst_rdata, + // AXI stream slave for destination stream from storage (BRAM/URAM/DDR/HBM) + // runs on m_axis_aclk and m_axis_aresetn + output s_storage_axis_ready, + input s_storage_axis_valid, + input [DST_DATA_WIDTH-1:0] s_storage_axis_data, + input s_storage_axis_last, + input [DST_DATA_WIDTH/8-1:0] s_storage_axis_tkeep, + + // Control interface for storage for m_storage_axis interface + output wr_request_enable, + output wr_request_valid, + input wr_request_ready, + output [MEM_SIZE_LOG2-1:0] wr_request_length, + input [MEM_SIZE_LOG2-1:0] wr_response_measured_length, + input wr_response_eot, + input wr_overflow, + + // Control interface for storage for s_storage_axis interface + output rd_request_enable, + output rd_request_valid, + input rd_request_ready, + output reg [MEM_SIZE_LOG2-1:0] rd_request_length, + input rd_response_eot, + input rd_underflow, // Status and monitor @@ -154,138 +170,82 @@ module data_offload #( wire src_clk; wire src_rstn; - wire src_valid_out_s; - wire [SRC_ADDR_WIDTH-1:0] src_wr_addr_s; - wire src_wr_ready_s; - wire src_wr_last_s; - wire [SRC_DATA_WIDTH/8-1:0] src_wr_tkeep_s; - wire dst_clk; wire dst_rstn; - wire [DST_ADDR_WIDTH-1:0] dst_raddr_s; - wire [DST_DATA_WIDTH-1:0] dst_mem_data_s; wire src_bypass_s; wire dst_bypass_s; wire oneshot_s; - wire [63:0] sample_count_s; wire [ 1:0] sync_config_s; wire sync_int_s; wire valid_bypass_s; wire [DST_DATA_WIDTH-1:0] data_bypass_s; wire ready_bypass_s; - wire [ 1:0] src_fsm_status_s; - wire [ 1:0] dst_fsm_status_s; - wire m_axis_valid_s; - wire m_axis_last_s; - wire [DST_DATA_WIDTH-1:0] m_axis_data_s; - wire dst_mem_valid_s; - wire dst_mem_valid_int_s; - wire m_axis_reset_int_s; + wire [ 4:0] src_fsm_status_s; + wire [ 3:0] dst_fsm_status_s; - wire [33:0] src_transfer_length_s; - wire src_wr_last_int_s; - wire [33:0] src_wr_last_beat_s; - - wire int_not_full; + wire [MEM_SIZE_LOG2-1:0] src_transfer_length_s; + wire [MEM_SIZE_LOG2-1:0] rd_wr_response_measured_length; + wire rd_ml_valid; + wire rd_ready; + wire rd_ml_ready; + wire wr_ready; assign src_clk = s_axis_aclk; assign dst_clk = m_axis_aclk; // internal registers - reg [33:0] src_data_counter = 0; - reg dst_mem_valid_d = 1'b0; - - generate - if (TX_OR_RXN_PATH) begin - assign src_wr_last_s = s_axis_last; - assign src_wr_tkeep_s = s_axis_tkeep; - assign m_axis_reset_int_s = ~dst_rstn; - end else begin - assign src_wr_last_s = src_wr_last_int_s; - assign src_wr_tkeep_s = {(SRC_DATA_WIDTH/8){1'b1}}; - assign m_axis_reset_int_s = ~dst_rstn | ~init_req; - end - endgenerate - assign fifo_src_wlast = src_wr_last_s; - // Offload FSM and control data_offload_fsm #( .TX_OR_RXN_PATH (TX_OR_RXN_PATH), - .WR_ADDRESS_WIDTH (SRC_ADDR_WIDTH), - .WR_DATA_WIDTH (SRC_DATA_WIDTH), - .RD_ADDRESS_WIDTH (DST_ADDR_WIDTH), - .RD_DATA_WIDTH (DST_DATA_WIDTH), - .SYNC_EXT_ADD_INTERNAL_CDC (SYNC_EXT_ADD_INTERNAL_CDC )) + .SYNC_EXT_ADD_INTERNAL_CDC (SYNC_EXT_ADD_INTERNAL_CDC)) i_data_offload_fsm ( .up_clk (up_clk), .wr_clk (src_clk), .wr_resetn_in (src_rstn), - .wr_resetn_out (fifo_src_resetn), - .wr_valid_in (s_axis_valid), - .wr_valid_out (fifo_src_wen), - .wr_ready (src_wr_ready_s), - .wr_addr (fifo_src_waddr), - .wr_last (src_wr_last_s), - .wr_tkeep (src_wr_tkeep_s), + .wr_request_enable (wr_request_enable), + .wr_request_valid (wr_request_valid), + .wr_request_ready (wr_request_ready), + .wr_response_eot (wr_response_eot), + .wr_ready (wr_ready), .rd_clk (dst_clk), .rd_resetn_in (dst_rstn), - .rd_resetn_out (fifo_dst_resetn), - .rd_ready (fifo_dst_ready_int_s), - .rd_valid (dst_mem_valid_s), - .rd_addr (fifo_dst_raddr), - .rd_last (), - .rd_tkeep (m_axis_tkeep), + .rd_request_enable (rd_request_enable), + .rd_request_valid (rd_request_valid), + .rd_request_ready (rd_request_ready), + .rd_response_eot (rd_response_eot), + .rd_ready (rd_ready), + .rd_valid (s_storage_axis_valid), + .rd_ml_valid (rd_ml_valid), + .rd_ml_ready (rd_ml_ready), .rd_oneshot (oneshot_s), + .wr_bypass (src_bypass_s), .init_req (init_req), - .init_ack (init_ack), .sync_config (sync_config_s), .sync_external (sync_ext), .sync_internal (sync_int_s), - .wr_fsm_state (src_fsm_status_s), - .rd_fsm_state (dst_fsm_status_s), - .sample_count (sample_count_s) + .wr_fsm_state_out (src_fsm_status_s), + .rd_fsm_state_out (dst_fsm_status_s) ); - // In case of external memory, read back can not start right after the write - // was finished (because of the CDC FIFOs and the latency of the EMIF - // interface) - generate - if (MEM_TYPE == 1'b1) begin - assign dst_mem_valid_int_s = dst_mem_valid_s; - end else begin - // Compensate the 1 cycle READ latency of the BRAM - always @(posedge m_axis_aclk) begin - dst_mem_valid_d <= dst_mem_valid_s; - end - assign dst_mem_valid_int_s = dst_mem_valid_d; - end - endgenerate + assign m_axis_valid = rd_ready & ((dst_bypass_s) ? valid_bypass_s : s_storage_axis_valid); + // For DAC paths set zero as IDLE data on the axis bus, avoid repeating last + // sample. + assign m_axis_data = TX_OR_RXN_PATH[0] & ~m_axis_valid ? {DST_DATA_WIDTH{1'b0}} : + (dst_bypass_s) ? data_bypass_s : s_storage_axis_data; + assign m_axis_last = (dst_bypass_s) ? 1'b0 : s_storage_axis_last; + assign m_axis_tkeep = (dst_bypass_s) ? {DST_DATA_WIDTH/8{1'b1}} : s_storage_axis_tkeep; - assign fifo_dst_ready_int_s = fifo_dst_ready & int_not_full; + assign s_axis_ready = wr_ready & ((src_bypass_s) ? ready_bypass_s : m_storage_axis_ready); - assign fifo_src_wdata = s_axis_data; - assign fifo_dst_ren = dst_mem_valid_s; + assign m_storage_axis_valid = s_axis_valid & wr_ready; + assign m_storage_axis_data = s_axis_data; + assign m_storage_axis_last = s_axis_last; + assign m_storage_axis_tkeep = s_axis_tkeep; - ad_axis_inf_rx #( - .DATA_WIDTH (DST_DATA_WIDTH)) - i_rx_axis_inf ( - .clk (m_axis_aclk), - .rst (m_axis_reset_int_s), - .valid (dst_mem_valid_int_s), - .data (fifo_dst_rdata), - .last (1'b0), - .inf_valid (m_axis_valid_s), - .inf_last (m_axis_last_s), - .inf_data (m_axis_data_s), - .inf_ready (m_axis_ready), - .int_not_full(int_not_full)); + assign s_storage_axis_ready = rd_ready & m_axis_ready; - assign m_axis_valid = (dst_bypass_s) ? valid_bypass_s : m_axis_valid_s; - assign m_axis_data = (dst_bypass_s) ? data_bypass_s : m_axis_data_s; - assign m_axis_last = (dst_bypass_s) ? 1'b0 : m_axis_last_s; - assign s_axis_ready = (src_bypass_s) ? ready_bypass_s : src_wr_ready_s; // Bypass module instance -- the same FIFO, just a smaller depth // NOTE: Generating an overflow is making sense just in BYPASS mode, and @@ -304,6 +264,8 @@ module data_offload #( .m_axis_tlast (), .m_axis_empty (), .m_axis_almost_empty (), + .m_axis_tkeep (), + .m_axis_level (), .s_axis_aclk (s_axis_aclk), .s_axis_aresetn (src_rstn), .s_axis_ready (ready_bypass_s), @@ -311,7 +273,9 @@ module data_offload #( .s_axis_data (s_axis_data), .s_axis_tlast (), .s_axis_full (), - .s_axis_almost_full () + .s_axis_almost_full (), + .s_axis_tkeep (), + .s_axis_room () ); // register map @@ -319,10 +283,11 @@ module data_offload #( data_offload_regmap #( .ID (ID), .MEM_TYPE (MEM_TYPE), - .MEM_SIZE (MEM_SIZE), + .MEM_SIZE_LOG2 (MEM_SIZE_LOG2), .TX_OR_RXN_PATH (TX_OR_RXN_PATH), - .AUTO_BRINGUP (AUTO_BRINGUP)) - i_regmap ( + .AUTO_BRINGUP (AUTO_BRINGUP), + .HAS_BYPASS (HAS_BYPASS) +) i_regmap ( .up_clk (up_clk), .up_rstn (up_rstn), .up_rreq (up_rreq_s), @@ -343,11 +308,12 @@ module data_offload #( .oneshot (oneshot_s), .sync (sync_int_s), .sync_config (sync_config_s), - .src_transfer_length (src_transfer_length_s), + .src_transfer_length (wr_request_length), + .dst_transfer_length (), .src_fsm_status (src_fsm_status_s), .dst_fsm_status (dst_fsm_status_s), - .sample_count_msb (sample_count_s[63:32]), - .sample_count_lsb (sample_count_s[31: 0]) + .src_overflow (wr_overflow), + .dst_underflow (rd_underflow) ); // axi interface wrapper @@ -386,30 +352,39 @@ module data_offload #( .up_rdata (up_rdata_s), .up_rack (up_rack_s)); -/* Beat counter on the source interface -* - * The storage unit can have size of a couple of Gbyte, which in case of an RX - * path would mean to fill up all that memory space before pushing over the - * stream to the RX DMA. (ADC can not generate a tlast) To make things more - * practical, user can set an arbitrary transfer length using the - * transfer_length register, which will be used to generate an internal tlast - * signal for the source FSM. If the register is set to zero, all the memory - * will be filled up, before passing control to the destination FSM. - * - */ +// Measured length handshake CDC +util_axis_fifo #( + .DATA_WIDTH(MEM_SIZE_LOG2), + .ADDRESS_WIDTH(0), + .ASYNC_CLK(1) +) i_measured_length_cdc ( + .s_axis_aclk(s_axis_aclk), + .s_axis_aresetn(s_axis_aresetn), + .s_axis_valid(wr_response_eot), + .s_axis_ready(), + .s_axis_full(), + .s_axis_data(wr_response_measured_length), + .s_axis_room(), + .s_axis_tkeep(), + .s_axis_tlast(), + .s_axis_almost_full(), -always @(posedge s_axis_aclk) begin - if (fifo_src_resetn == 1'b0) begin // counter should reset when source FMS resets - src_data_counter <= 0; - end else begin - if (fifo_src_wen & src_wr_ready_s) begin - src_data_counter <= src_data_counter + 1'b1; - end - end + .m_axis_aclk(m_axis_aclk), + .m_axis_aresetn(m_axis_aresetn), + .m_axis_valid(rd_ml_valid), + .m_axis_ready(rd_ml_ready), + .m_axis_data(rd_wr_response_measured_length), + .m_axis_level(), + .m_axis_empty(), + .m_axis_tkeep(), + .m_axis_tlast(), + .m_axis_almost_empty() +); + +always @(posedge m_axis_aclk) begin + if (rd_ml_valid & rd_ml_ready) + rd_request_length <= rd_wr_response_measured_length; end -// transfer length is in bytes, but counter monitors the source data beats -assign src_wr_last_beat_s = (src_transfer_length_s == 'h0) ? MEM_SIZE[33:SRC_BEAT_BYTE]-1 : src_transfer_length_s[33:SRC_BEAT_BYTE]-1; -assign src_wr_last_int_s = (src_data_counter == src_wr_last_beat_s) ? 1'b1 : 1'b0; endmodule diff --git a/library/data_offload/data_offload_constr.ttcl b/library/data_offload/data_offload_constr.ttcl index 47c5f717a..97d4a1814 100644 --- a/library/data_offload/data_offload_constr.ttcl +++ b/library/data_offload/data_offload_constr.ttcl @@ -6,6 +6,7 @@ <: set mem_type [getBooleanValue "MEM_TYPE"] :> <: set tx_enable [getBooleanValue "TX_OR_RXN_PATH"] :> <: set internal_cdc [getBooleanValue "SYNC_EXT_ADD_INTERNAL_CDC"] :> +<: set has_bypass [getBooleanValue "HAS_BYPASS"] :> ## for all synchronization registers from util_cdc modules set_property ASYNC_REG TRUE \ @@ -13,7 +14,7 @@ set_property ASYNC_REG TRUE \ [get_cells -hier {*cdc_sync_stage2_reg*}] ## For RX in case of BRAMs -<: if { $tx_enable == 0 } { :> +<: if { !$tx_enable } { :> <: if { $internal_cdc } { :> set_false_path \ @@ -32,22 +33,10 @@ set_false_path \ -from [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/out_toggle_d1_reg/C}] \ -to [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/i_sync_in/cdc_sync_stage1_reg[*]/D}] -<: if { !$mem_type } { :> - - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*adc_init_sync.i_rd_init_ack_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*adc_init_sync.i_rd_init_ack_sync/i_sync_out/cdc_sync_stage1_reg[*]/D}] - - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*adc_init_sync.i_rd_init_ack_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*adc_init_sync.i_rd_init_ack_sync/i_sync_in/cdc_sync_stage1_reg[*]/D}] - -<: } :> - <: } :> ## For TX in case of BRAMs -<: if { $tx_enable == 1 } { :> +<: if { $tx_enable } { :> <: if { $internal_cdc } { :> set_false_path \ @@ -55,23 +44,11 @@ set_false_path \ <: } :> -<: if { !$mem_type } { :> - - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*dac_init_sync.i_wr_init_ack_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*dac_init_sync.i_wr_init_ack_sync/i_sync_out/cdc_sync_stage1_reg[*]/D}] - - set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*dac_init_sync.i_wr_init_ack_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*dac_init_sync.i_wr_init_ack_sync/i_sync_in/cdc_sync_stage1_reg[*]/D}] - -<: } :> - <: } :> ## For external DDRx memory -<: if { $mem_type == 1 } { :> +<: if { $mem_type } { :> set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_ddr_calib_done_sync/cdc_sync_stage1_reg[0]/D}] @@ -80,18 +57,6 @@ set_false_path \ ## Common constraints -set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*/i_xfer_status/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_xfer_status/i_sync_out/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*/i_xfer_status/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_xfer_status/i_sync_in/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -from [get_cells -hierarchical * -filter {NAME=~*/i_xfer_status/cdc_hold_reg[*]}] \ - -to [get_cells -hierarchical * -filter {NAME=~*/i_xfer_status/out_data_reg[*]}] - set_false_path \ -from [get_pins -hierarchical * -filter {NAME=~*/i_dst_fsm_status/in_toggle_d1_reg/C}] \ -to [get_pins -hierarchical * -filter {NAME=~*/i_dst_fsm_status/i_sync_out/cdc_sync_stage1_reg[*]/D}] @@ -124,22 +89,6 @@ set_false_path \ -from [get_pins -hierarchical * -filter {NAME=~*/i_wr_empty_sync/out_toggle_d1_reg/C}] \ -to [get_pins -hierarchical * -filter {NAME=~*/i_wr_empty_sync/i_sync_in/cdc_sync_stage1_reg[*]/D}] -set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*/i_rd_full_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_rd_full_sync/i_sync_out/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*/i_rd_full_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_rd_full_sync/i_sync_in/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*/i_rd_wr_last_sync/out_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_rd_wr_last_sync/i_sync_in/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -from [get_pins -hierarchical * -filter {NAME=~*/i_rd_wr_last_sync/in_toggle_d1_reg/C}] \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_rd_wr_last_sync/i_sync_out/cdc_sync_stage1_reg[*]/D}] - set_false_path \ -from [get_pins -hierarchical * -filter {NAME=~*i_sync_xfer_control/in_toggle_d1_reg/C}] \ -to [get_pins -hierarchical * -filter {NAME=~*i_sync_xfer_control/i_sync_out/cdc_sync_stage1_reg[*]/D}] @@ -153,20 +102,13 @@ set_false_path \ -to [get_cells -hierarchical * -filter {NAME=~*i_sync_xfer_control/out_data_reg[*]}] +<: if { $tx_enable } { :> set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_rd_init_req_sync/cdc_sync_stage1_reg[*]/D}] - +<: } else { :> set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_wr_init_req_sync/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -to [get_pins -hierarchical * -filter {NAME=~*i_wr_oneshot_sync/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_rd_last_address/cdc_sync_stage1_reg[*]/D}] - -set_false_path \ - -to [get_pins -hierarchical * -filter {NAME=~*/i_rd_last_keep/cdc_sync_stage1_reg[*]/D}] +<: } :> set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_src_xfer_control/cdc_sync_stage1_reg[*]/D}] @@ -177,10 +119,48 @@ set_false_path \ set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_dst_oneshot_sync/cdc_sync_stage1_reg[0]/D}] -## Constraints for the bypass module +# measured transfer length util_axis_fifo +set src_clk [get_clocks -of_objects [get_ports s_axis_aclk]] +set dest_clk [get_clocks -of_objects [get_ports m_axis_aclk]] + +set_max_delay -quiet -datapath_only \ + -from $src_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_measured_length_cdc/zerodeep.i_waddr_sync* && IS_SEQUENTIAL}] \ + [get_property -min PERIOD $src_clk] + +set_max_delay -quiet -datapath_only \ + -from $dest_clk \ + -to [get_cells -quiet -hier *cdc_sync_stage1_reg* \ + -filter {NAME =~ *i_measured_length_cdc/zerodeep.i_raddr_sync* && IS_SEQUENTIAL}] \ + [get_property -min PERIOD $dest_clk] + +set_max_delay -quiet -datapath_only \ + -from [get_cells -quiet -hier *cdc_sync_fifo_ram_reg* \ + -filter {NAME =~ *i_measured_length_cdc* && IS_SEQUENTIAL}] \ + -to $dest_clk \ + [get_property -min PERIOD $dest_clk] + +## Constraints for the bypass module +<: if { $has_bypass } { :> set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_waddr_sync_gray/cdc_sync_stage1_reg[*]/D}] set_false_path \ -to [get_pins -hierarchical * -filter {NAME=~*i_raddr_sync_gray/cdc_sync_stage1_reg[*]/D}] +<: } :> + +## Constraints for the overflow/underflow status +<: if { $tx_enable } { :> +set flow_cdc i_rd_underflow_sync +<: } else { :> +set flow_cdc i_wr_overflow_sync +<: } :> +set_false_path \ + -from [get_pins -hierarchical * -filter NAME=~*/$flow_cdc/in_toggle_d1_reg/C] \ + -to [get_pins -hierarchical * -filter NAME=~*/$flow_cdc/i_sync_out/cdc_sync_stage1_reg[*]/D] + +set_false_path \ + -from [get_pins -hierarchical * -filter NAME=~*/$flow_cdc/out_toggle_d1_reg/C] \ + -to [get_pins -hierarchical * -filter NAME=~*/$flow_cdc/i_sync_in/cdc_sync_stage1_reg[*]/D] diff --git a/library/data_offload/data_offload_fsm.v b/library/data_offload/data_offload_fsm.v index 87a258ab1..5d6ccfb79 100644 --- a/library/data_offload/data_offload_fsm.v +++ b/library/data_offload/data_offload_fsm.v @@ -41,61 +41,75 @@ module data_offload_fsm #( parameter TX_OR_RXN_PATH = 0, - parameter WR_ADDRESS_WIDTH = 4, - parameter WR_DATA_WIDTH = 128, - parameter RD_ADDRESS_WIDTH = 4, - parameter RD_DATA_WIDTH = 128, parameter SYNC_EXT_ADD_INTERNAL_CDC = 1) ( input up_clk, + // Control interface for storage for m_storage_axis interface + output reg wr_request_enable = 1'b0, + output wr_request_valid, + input wr_request_ready, + input wr_response_eot, + + // Control interface for storage for s_storage_axis interface + output reg rd_request_enable = 1'b0, + output rd_request_valid, + input rd_request_ready, + input rd_response_eot, + + input rd_ml_valid, + output rd_ml_ready, + + // Data path gating + output wr_ready, + output rd_ready, + input rd_valid, + // write control interface input wr_clk, input wr_resetn_in, - output reg wr_resetn_out, - input wr_valid_in, - output wr_valid_out, - output wr_ready, - output reg [WR_ADDRESS_WIDTH-1:0] wr_addr, - input wr_last, - input [WR_DATA_WIDTH/8-1:0] wr_tkeep, + input wr_bypass, // read control interface input rd_clk, input rd_resetn_in, - output reg rd_resetn_out, - input rd_ready, - output reg rd_valid = 1'b0, - output reg [RD_ADDRESS_WIDTH-1:0] rd_addr, - output rd_last, - output reg [RD_DATA_WIDTH/8-1:0] rd_tkeep, input rd_oneshot, // 0 - CYCLIC; 1 - ONE_SHOT; - // Synchronization interface - synchronous to the device clock (ADC or DAC) + // Synchronization interface - synchronous to the external DMA clock input init_req, - output init_ack, input [ 1:0] sync_config, input sync_external, input sync_internal, // FSM debug - output [ 1:0] wr_fsm_state, - output [ 1:0] rd_fsm_state, - output reg [63:0] sample_count + output [ 4:0] wr_fsm_state_out, + output [ 3:0] rd_fsm_state_out ); // FSM states - localparam WR_IDLE = 2'b00; - localparam WR_SYNC = 2'b01; - localparam WR_WRITE_TO_MEM = 2'b11; - localparam WR_WAIT_TO_END = 2'b10; + localparam WR_STATE_IDLE = 5'b00001; + localparam WR_STATE_PRE_WR = 5'b00010; + localparam WR_STATE_SYNC = 5'b00100; + localparam WR_STATE_WR = 5'b01000; + localparam WR_STATE_WAIT_RD = 5'b10000; - localparam RD_IDLE = 2'b00; - localparam RD_SYNC = 2'b01; - localparam RD_READ_FROM_MEM = 2'b11; + localparam WR_BIT_IDLE = 0; + localparam WR_BIT_PRE_WR = 1; + localparam WR_BIT_SYNC = 2; + localparam WR_BIT_WR = 3; + + localparam RD_STATE_IDLE = 4'b0001; + localparam RD_STATE_PRE_RD = 4'b0010; + localparam RD_STATE_SYNC = 4'b0100; + localparam RD_STATE_RD = 4'b1000; + + localparam RD_BIT_IDLE = 0; + localparam RD_BIT_PRE_RD = 1; + localparam RD_BIT_SYNC = 2; + localparam RD_BIT_RD = 3; // Synchronization options @@ -103,352 +117,173 @@ module data_offload_fsm #( localparam HARDWARE = 2'b01; localparam SOFTWARE = 2'b10; - // helper parameters for last address, tkeep conversion - localparam LSB = (WR_ADDRESS_WIDTH > RD_ADDRESS_WIDTH) ? WR_ADDRESS_WIDTH - RD_ADDRESS_WIDTH : - RD_ADDRESS_WIDTH - WR_ADDRESS_WIDTH; - localparam POW2_LSB = 1 << LSB; - // internal registers - - reg [WR_ADDRESS_WIDTH-1:0] wr_last_addr; - reg [WR_DATA_WIDTH/8-1:0] wr_last_keep; - - reg [RD_DATA_WIDTH/8-1:0] rd_tkeep_last; - reg [RD_ADDRESS_WIDTH-1:0] rd_last_addr; - reg rd_isempty; - reg rd_init_req_d; - reg wr_init_req_d; - reg wr_ready_d; + reg rd_cyclic_en = 1'b0; // internal signals + wire wr_sync_external_s; + wire wr_init_req_s; + wire wr_rd_response_eot; + wire rd_sync_external_s; + wire rd_last_eot; + wire rd_init_req_s; - wire wr_almost_full; - wire wr_init_req_s; - wire wr_init_req_pos_s; - wire wr_init_ack_s; - wire rd_isfull_s; - wire wr_isempty_s; - wire rd_empty_s; - wire rd_wr_last_s; - wire rd_init_req_s; - wire rd_init_req_neg_s; - wire rd_init_ack_s; - wire [WR_ADDRESS_WIDTH-1:0] rd_wr_last_addr_s; - wire [WR_DATA_WIDTH/8-1:0] rd_wr_last_tkeep_s; - wire wr_sync_external_s; - wire rd_sync_external_s; - wire wr_oneshot; + reg [4:0] wr_fsm_state = WR_STATE_IDLE; + reg [4:0] wr_fsm_next_state; + reg [3:0] rd_fsm_state = RD_STATE_IDLE; + reg [3:0] rd_fsm_next_state; + reg [1:0] rd_outstanding = 2'd0; - (* DONT_TOUCH = "TRUE" *) reg [1:0] wr_fsm_state = 2'b00; - (* DONT_TOUCH = "TRUE" *) reg [1:0] rd_fsm_state = 2'b00; + assign wr_fsm_state_out = wr_fsm_state; + assign rd_fsm_state_out = rd_fsm_state; - // Mealy state machine for write control - always @(posedge wr_clk) begin - if (wr_resetn_in == 1'b0) begin - wr_fsm_state <= WR_IDLE; - end else begin - case (wr_fsm_state) - - WR_IDLE: begin - if (wr_init_req_s) begin - wr_fsm_state <= (TX_OR_RXN_PATH) ? WR_WRITE_TO_MEM : WR_SYNC; - end else begin - wr_fsm_state <= WR_IDLE; + always @(*) begin + wr_fsm_next_state = wr_fsm_state; + case (wr_fsm_state) + WR_STATE_IDLE: + if (wr_init_req_s & ~wr_bypass) begin + wr_fsm_next_state = WR_STATE_PRE_WR; + end + WR_STATE_PRE_WR: + if (wr_request_ready) begin + wr_fsm_next_state = TX_OR_RXN_PATH ? WR_STATE_WR : WR_STATE_SYNC; + end + WR_STATE_SYNC: + case (sync_config) + AUTOMATIC: + wr_fsm_next_state = WR_STATE_WR; + HARDWARE: + if (wr_sync_external_s) begin + wr_fsm_next_state = WR_STATE_WR; end - end - - WR_SYNC: begin - // do not lock the FSM if something goes wrong - if (TX_OR_RXN_PATH) begin - wr_fsm_state <= WR_WRITE_TO_MEM; - end else begin // SOURCE_IS_BACK_END - case (sync_config) - AUTOMATIC: begin - wr_fsm_state <= WR_WRITE_TO_MEM; - end - HARDWARE: begin - if (wr_sync_external_s) begin - wr_fsm_state <= WR_WRITE_TO_MEM; - end - end - SOFTWARE: begin - if (sync_internal) begin - wr_fsm_state <= WR_WRITE_TO_MEM; - end - end - default: begin - wr_fsm_state <= WR_WRITE_TO_MEM; - end - endcase + SOFTWARE: + if (sync_internal) begin + wr_fsm_next_state = WR_STATE_WR; end - end - - WR_WRITE_TO_MEM: begin - if ((wr_full || wr_last) && wr_valid_out) begin - wr_fsm_state <= WR_WAIT_TO_END; - end else begin - wr_fsm_state <= WR_WRITE_TO_MEM; - end - end - - WR_WAIT_TO_END: begin - if (wr_isempty_s && (wr_oneshot || wr_init_req_s)) begin - wr_fsm_state <= WR_IDLE; - end else begin - wr_fsm_state <= WR_WAIT_TO_END; - end - end - - default: wr_fsm_state <= WR_IDLE; - endcase - - end - end - - // the initialization interface (init_req) is edge sensitive - always @(posedge wr_clk) begin - wr_init_req_d <= wr_init_req_s; - end - assign wr_init_req_pos_s = ~wr_init_req_d & wr_init_req_s; - - // status bits - assign wr_almost_full = (wr_addr == {{(WR_ADDRESS_WIDTH-1){1'b1}}, 1'b0}) ? 1'b1 : 1'b0; - assign wr_full = &wr_addr; - - // generate INIT acknowledge signal in WRITE domain (in case of ADCs) - assign wr_init_ack_s = (wr_fsm_state == WR_SYNC) ? 1'b1 : 1'b0; - - // write address generation - always @(posedge wr_clk) begin - if ((wr_resetn_in == 1'b0) || (wr_fsm_state == WR_IDLE)) begin - wr_addr <= 'b0; - end else begin - if (wr_valid_out) begin - wr_addr <= wr_addr + 1'b1; - end - end - end - - // reset the storage unit's FMS before each transfer - always @(posedge wr_clk) begin - if ((wr_resetn_in == 1'b0) || (wr_fsm_state == WR_IDLE)) begin - wr_resetn_out <= 1'b0; - end else begin - wr_resetn_out <= 1'b1; - end + default: + wr_fsm_next_state = WR_STATE_WR; + endcase + WR_STATE_WR: + if (wr_response_eot) begin + wr_fsm_next_state = WR_STATE_WAIT_RD; + end + WR_STATE_WAIT_RD: + if (wr_rd_response_eot) begin + wr_fsm_next_state = WR_STATE_IDLE; + end + default: + wr_fsm_next_state = WR_STATE_IDLE; + endcase end always @(posedge wr_clk) begin if (wr_resetn_in == 1'b0) begin - wr_last_addr <= {WR_ADDRESS_WIDTH{1'b1}}; + wr_fsm_state <= WR_STATE_IDLE; end else begin - wr_last_addr <= (wr_valid_out) ? wr_addr : wr_last_addr; + wr_fsm_state <= wr_fsm_next_state; end end - always @(posedge wr_clk) begin - if (wr_resetn_in == 1'b0) begin - wr_last_keep <= {WR_DATA_WIDTH/8{1'b1}}; - end else begin - if (wr_last) begin - // if the SOURCE is at back-end, the interface is FIFO, set the tkeep - // to its default - wr_last_keep <= (TX_OR_RXN_PATH) ? wr_tkeep : {WR_DATA_WIDTH/8{1'b1}}; - end - end - end - - always @(posedge wr_clk) begin - wr_ready_d <= wr_ready && !(wr_valid_in && wr_last); - end - - // flush out the DMA if the transfer is bigger than the storage size - assign wr_ready = ((wr_fsm_state == WR_WRITE_TO_MEM) || - (TX_OR_RXN_PATH && ((wr_fsm_state == WR_WAIT_TO_END) && wr_ready_d))) ? 1'b1 : 1'b0; - - // write control - assign wr_valid_out = (wr_fsm_state == WR_WRITE_TO_MEM) & wr_valid_in; - - // sample counter for debug purposes, the value of the counter resets at - // every new incoming request - - always @(posedge wr_clk) begin - if (wr_init_req_pos_s == 1'b1) begin - sample_count <= 64'b0; - end else begin - if (wr_ready && wr_valid_in) begin - sample_count <= sample_count + 1'b1; - end - end - end - - // Mealy state machine for read control - always @(posedge rd_clk) begin - if (rd_resetn_in == 1'b0) begin - rd_fsm_state <= RD_IDLE; - end else begin - case (rd_fsm_state) - - RD_IDLE: begin - if (((!TX_OR_RXN_PATH) & rd_isfull_s) || (rd_wr_last_s)) begin - if (TX_OR_RXN_PATH) begin - rd_fsm_state <= RD_SYNC; - end else begin - rd_fsm_state <= RD_READ_FROM_MEM; + always @(*) begin + rd_fsm_next_state = rd_fsm_state; + case (rd_fsm_state) + RD_STATE_IDLE: + if (rd_ml_valid) begin + rd_fsm_next_state = RD_STATE_PRE_RD; + end + RD_STATE_PRE_RD: + if (rd_request_ready) begin + rd_fsm_next_state = TX_OR_RXN_PATH ? RD_STATE_SYNC : RD_STATE_RD; + end + RD_STATE_SYNC: + if (rd_valid) // Wait until storage is valid + case (sync_config) + AUTOMATIC: + rd_fsm_next_state = RD_STATE_RD; + HARDWARE: + if (rd_sync_external_s) begin + rd_fsm_next_state = RD_STATE_RD; end - end else begin - rd_fsm_state <= RD_IDLE; - end - end - - RD_SYNC : begin - // do not lock the FSM if something goes wrong - if (!TX_OR_RXN_PATH) begin - rd_fsm_state <= RD_READ_FROM_MEM; - end else begin // TX_OR_RXN_PATH - case (sync_config) - AUTOMATIC: begin - rd_fsm_state <= RD_READ_FROM_MEM; - end - HARDWARE: begin - if (rd_sync_external_s) begin - rd_fsm_state <= RD_READ_FROM_MEM; - end - end - SOFTWARE: begin - if (sync_internal) begin - rd_fsm_state <= RD_READ_FROM_MEM; - end - end - default: begin - rd_fsm_state <= RD_READ_FROM_MEM; - end - endcase - end - end - - // read until empty or next init_req - RD_READ_FROM_MEM : begin - if (rd_empty_s && rd_ready) begin - if (rd_init_req_s || (rd_oneshot && rd_last)) begin - rd_fsm_state <= RD_IDLE; - end else if (TX_OR_RXN_PATH && sync_config && (!rd_oneshot)) begin - rd_fsm_state <= RD_SYNC; - end else begin - rd_fsm_state <= RD_READ_FROM_MEM; + SOFTWARE: + if (sync_internal) begin + rd_fsm_next_state = RD_STATE_RD; end - end else begin - rd_fsm_state <= RD_READ_FROM_MEM; - end + default: + rd_fsm_next_state = RD_STATE_RD; + endcase + RD_STATE_RD: + if (rd_last_eot) begin + rd_fsm_next_state = (rd_cyclic_en == 1'b0) ? RD_STATE_IDLE : + (TX_OR_RXN_PATH & (sync_config != AUTOMATIC)) ? RD_STATE_SYNC : + RD_STATE_RD; end - - default : rd_fsm_state <= RD_IDLE; - endcase - end - end - - // the initialization interface (init_req) is edge sensitive - // TODO: This should be redefined! Will work only of init_req is active - // during the whole DMA transfer (use xfer_req for driving init_req) - always @(posedge rd_clk) begin - rd_init_req_d <= rd_init_req_s; - end - assign rd_init_req_neg_s = rd_init_req_d & ~rd_init_req_s; - - // generate INIT acknowledge signal in WRITE domain (in case of ADCs) - assign rd_init_ack_s = (rd_fsm_state == RD_SYNC) ? 1'b1 : 1'b0; - - // Reset the storage unit's FSM before each transfer - always @(posedge rd_clk) begin - if ((rd_resetn_in == 1'b0) || (rd_fsm_state == RD_IDLE)) begin - rd_resetn_out <= 1'b0; - end else begin - rd_resetn_out <= 1'b1; - end - end - - // read address generation - always @(posedge rd_clk) begin - if (rd_fsm_state != RD_READ_FROM_MEM) begin - rd_addr <= 'b0; - end else begin - if (rd_valid) begin - if (rd_oneshot) - rd_addr <= (rd_last_addr == rd_addr) ? rd_addr : rd_addr + 1'b1; - else - rd_addr <= (rd_last_addr == rd_addr) ? {RD_ADDRESS_WIDTH{1'b0}} : rd_addr + 1'b1; - end - end - end - - assign rd_empty_s = (rd_addr == rd_last_addr) ? 1'b1 : 1'b0; - assign rd_last = rd_oneshot & rd_empty_s; - always @(posedge rd_clk) begin - if (rd_resetn_in == 1'b0) begin - rd_isempty <= 1'b0; - end else begin - rd_isempty <= rd_empty_s; - end + default: + rd_fsm_next_state = RD_STATE_IDLE; + endcase end always @(posedge rd_clk) begin if (rd_resetn_in == 1'b0) begin - rd_valid <= 1'b0; + rd_fsm_state <= RD_STATE_IDLE; end else begin - if ((rd_ready) && (rd_fsm_state == RD_READ_FROM_MEM) && !(rd_valid && rd_last && rd_oneshot)) begin - rd_valid <= 1'b1; - end else begin - rd_valid <= 1'b0; - end + rd_fsm_state <= rd_fsm_next_state; end end + always @(posedge rd_clk) begin + if (rd_resetn_in == 1'b0) + rd_outstanding <= 2'b0; + else if (rd_request_ready & rd_request_valid & ~rd_response_eot) + rd_outstanding <= rd_outstanding + 2'd1; + else if (~(rd_request_ready & rd_request_valid) & (rd_response_eot & rd_fsm_state[RD_BIT_RD])) + rd_outstanding <= rd_outstanding - 2'd1; + end + assign rd_last_eot = (rd_outstanding == 1) & (rd_response_eot & rd_fsm_state[RD_BIT_RD]) & !(rd_request_ready & rd_request_valid); + + always @(posedge rd_clk) begin + if (rd_init_req_s) begin + rd_cyclic_en <= 1'b0; + end else if (rd_fsm_state[RD_BIT_PRE_RD]) begin + rd_cyclic_en <= ~rd_oneshot; + end + end + + assign rd_ready = rd_fsm_state[RD_BIT_RD]; + assign wr_ready = wr_fsm_state[WR_BIT_WR]; + + assign wr_request_valid = wr_fsm_state[WR_BIT_PRE_WR]; + assign rd_request_valid = rd_fsm_state[RD_BIT_PRE_RD] | rd_cyclic_en; + + always @(posedge rd_clk) begin + if (rd_resetn_in == 1'b0 || (~rd_init_req_s & ~TX_OR_RXN_PATH[0])) + rd_request_enable <= 1'b0; + else + rd_request_enable <= 1'b1; + end + + always @(posedge wr_clk) begin + if (wr_resetn_in == 1'b0) + wr_request_enable <= 1'b0; + else + wr_request_enable <= 1'b1; + end + + assign rd_ml_ready = rd_fsm_state[RD_BIT_IDLE]; + // CDC circuits - sync_event #( .NUM_OF_EVENTS (1), .ASYNC_CLK (1)) i_wr_empty_sync ( .in_clk (rd_clk), - .in_event (rd_isempty), + .in_event (rd_last_eot && rd_fsm_state[RD_BIT_RD]), .out_clk (wr_clk), - .out_event (wr_isempty_s) - ); - - sync_event #( - .NUM_OF_EVENTS (1), - .ASYNC_CLK(1)) - i_rd_full_sync ( - .in_clk (wr_clk), - .in_event (wr_almost_full), - .out_clk (rd_clk), - .out_event (rd_isfull_s) - ); - - sync_event #( - .NUM_OF_EVENTS (1), - .ASYNC_CLK (1)) - i_rd_wr_last_sync ( - .in_clk (wr_clk), - .in_event ((wr_last & wr_valid_in)), - .out_clk (rd_clk), - .out_event (rd_wr_last_s) + .out_event (wr_rd_response_eot) ); sync_bits #( .NUM_OF_BITS (1), - .ASYNC_CLK (1)) - i_wr_oneshot_sync ( - .in_bits (rd_oneshot), - .out_clk (wr_clk), - .out_resetn (1'b1), - .out_bits (wr_oneshot) - ); - - - sync_bits #( - .NUM_OF_BITS (1), - .ASYNC_CLK (1)) + .ASYNC_CLK (TX_OR_RXN_PATH[0])) i_rd_init_req_sync ( .in_bits (init_req), .out_clk (rd_clk), @@ -458,7 +293,7 @@ module data_offload_fsm #( sync_bits #( .NUM_OF_BITS (1), - .ASYNC_CLK (1)) + .ASYNC_CLK (~TX_OR_RXN_PATH[0])) i_wr_init_req_sync ( .in_bits (init_req), .out_clk (wr_clk), @@ -466,102 +301,6 @@ module data_offload_fsm #( .out_bits (wr_init_req_s) ); - generate if (TX_OR_RXN_PATH == 0) begin : adc_init_sync - - sync_event #( - .NUM_OF_EVENTS (1), - .ASYNC_CLK (1)) - i_rd_init_ack_sync ( - .in_clk (wr_clk), - .in_event (wr_init_ack_s), - .out_clk (rd_clk), - .out_event (init_ack) - ); - - end else begin : dac_init_sync - - sync_event #( - .NUM_OF_EVENTS (1), - .ASYNC_CLK (1)) - i_wr_init_ack_sync ( - .in_clk (rd_clk), - .in_event (rd_init_ack_s), - .out_clk (wr_clk), - .out_event (init_ack) - ); - - end - endgenerate - - // convert write address and last/keep to read address and last/keep - - sync_bits #( - .NUM_OF_BITS (WR_ADDRESS_WIDTH), - .ASYNC_CLK (1)) - i_rd_last_address ( - .in_bits (wr_last_addr), - .out_clk (rd_clk), - .out_resetn (1'b1), - .out_bits (rd_wr_last_addr_s) - ); - - sync_bits #( - .NUM_OF_BITS (WR_DATA_WIDTH/8), - .ASYNC_CLK (1)) - i_rd_last_keep ( - .in_bits (wr_last_keep), - .out_clk (rd_clk), - .out_resetn (1'b1), - .out_bits (rd_wr_last_tkeep_s) - ); - - // upsizing - WR_DATA_WIDTH < RD_DATA_WIDTH - generate if (WR_ADDRESS_WIDTH > RD_ADDRESS_WIDTH) begin - - always @(posedge rd_clk) begin - rd_last_addr <= rd_wr_last_addr_s[WR_ADDRESS_WIDTH-1 : LSB]; - end - - // the read tkeep will be wider than the write tkeep, and its value - // depends on when the write tlast was asserted - always @(posedge rd_clk) begin :tkeep_gen - integer i; - for (i = 0; i < POW2_LSB; i = i + 1) begin : a_tkeep - if (rd_last_addr[LSB-1:0] < i) - rd_tkeep_last[(i+1)*WR_DATA_WIDTH/8-1 -: WR_DATA_WIDTH/8] <= {WR_DATA_WIDTH/8{1'b0}}; - else - rd_tkeep_last[(i+1)*WR_DATA_WIDTH/8-1 -: WR_DATA_WIDTH/8] <= (i == 0) ? rd_wr_last_tkeep_s : {WR_DATA_WIDTH/8{1'b1}}; - end - end - - end else if (WR_ADDRESS_WIDTH < RD_ADDRESS_WIDTH) begin // downsizing - WR_DATA_WIDTH > RD_DATA_WIDTH or equal - - always @(posedge rd_clk) begin - rd_tkeep_last <= rd_wr_last_tkeep_s[RD_DATA_WIDTH/8-1 : 0]; - rd_last_addr <= {rd_wr_last_addr_s, {LSB{1'b1}}}; - end - - end else begin - - always @(posedge rd_clk) begin - rd_tkeep_last <= rd_wr_last_tkeep_s; - rd_last_addr <= rd_wr_last_addr_s; - end - - end - endgenerate - - always @(posedge rd_clk) begin - if (rd_fsm_state == RD_IDLE) begin - rd_tkeep <= {(RD_DATA_WIDTH/8){1'b1}}; - end else begin - if (rd_empty_s && rd_ready) - rd_tkeep <= rd_tkeep_last; - else if (rd_ready) - rd_tkeep <= {(RD_DATA_WIDTH/8){1'b1}}; - end - end - // When SYNC_EXT_ADD_INTERNAL_CDC is deasserted, one of these signals will end // up being synchronized to the "wrong" clock domain. This shouldn't matter // because the incorrectly synchronized signal is guarded by a synthesis constant. diff --git a/library/data_offload/data_offload_ip.tcl b/library/data_offload/data_offload_ip.tcl index 13e4b66bb..d7ae378c3 100644 --- a/library/data_offload/data_offload_ip.tcl +++ b/library/data_offload/data_offload_ip.tcl @@ -41,7 +41,6 @@ adi_add_bus "m_axis" "master" \ {"m_axis_data" "TDATA"} \ {"m_axis_last" "TLAST"} \ {"m_axis_tkeep" "TKEEP"} ] -adi_add_bus_clock "m_axis_aclk" "m_axis" "m_axis_aresetn" ## source interface (e.g. TX_DMA or ADC core) @@ -54,14 +53,75 @@ adi_add_bus "s_axis" "slave" \ {"s_axis_data" "TDATA"} \ {"s_axis_last" "TLAST"} \ {"s_axis_tkeep" "TKEEP"} ] -adi_add_bus_clock "s_axis_aclk" "s_axis" "s_axis_aresetn" + +adi_add_bus "wr_ctrl" "master" \ + "analog.com:interface:if_do_ctrl_rtl:1.0" \ + "analog.com:interface:if_do_ctrl:1.0" \ + [list {"wr_request_enable" "request_enable"} \ + {"wr_request_valid" "request_valid"} \ + {"wr_request_ready" "request_ready"} \ + {"wr_request_length" "request_length"} \ + {"wr_response_measured_length" "response_measured_length"} \ + {"wr_response_eot" "response_eot"} \ + {"wr_overflow" "status_overflow"} \ + ] + +adi_add_bus "rd_ctrl" "master" \ + "analog.com:interface:if_do_ctrl_rtl:1.0" \ + "analog.com:interface:if_do_ctrl:1.0" \ + [list {"rd_request_enable" "request_enable"} \ + {"rd_request_valid" "request_valid"} \ + {"rd_request_ready" "request_ready"} \ + {"rd_request_length" "request_length"} \ + {"rd_response_eot" "response_eot"} \ + {"rd_underflow" "status_underflow"} \ + ] + +adi_add_bus "s_storage_axis" "slave" \ + "xilinx.com:interface:axis_rtl:1.0" \ + "xilinx.com:interface:axis:1.0" \ + [list {"s_storage_axis_ready" "TREADY"} \ + {"s_storage_axis_valid" "TVALID"} \ + {"s_storage_axis_data" "TDATA"} \ + {"s_storage_axis_tkeep" "TKEEP"} \ + {"s_storage_axis_last" "TLAST"}] + +adi_add_bus "m_storage_axis" "master" \ + "xilinx.com:interface:axis_rtl:1.0" \ + "xilinx.com:interface:axis:1.0" \ + [list {"m_storage_axis_ready" "TREADY"} \ + {"m_storage_axis_valid" "TVALID"} \ + {"m_storage_axis_data" "TDATA"} \ + {"m_storage_axis_tkeep" "TKEEP"} \ + {"m_storage_axis_last" "TLAST"}] + +adi_add_bus_clock "m_axis_aclk" "s_storage_axis:m_axis" "m_axis_aresetn" +adi_add_bus_clock "s_axis_aclk" "m_storage_axis:s_axis" "s_axis_aresetn" set cc [ipx::current_core] +set_property -dict [list \ + enablement_resolve_type dependent \ + driver_value 0 \ + enablement_dependency {MEM_TYPE == 1} \ + ] \ +[ipx::get_ports ddr_calib_done -of_objects $cc] + +set_property -dict [list \ + driver_value 0 \ + ] \ +[ipx::get_ports wr_overflow -of_objects $cc] + +set_property -dict [list \ + driver_value 0 \ + ] \ +[ipx::get_ports rd_underflow -of_objects $cc] + ## Parameter validations ## MEM_TPYE set_property -dict [list \ + "value_format" "long" \ "value_validation_type" "pairs" \ "value_validation_pairs" { \ "Internal memory" "0" \ @@ -70,6 +130,11 @@ set_property -dict [list \ ] \ [ipx::get_user_parameters MEM_TYPE -of_objects $cc] +set_property -dict [list \ + "value_format" "long" \ + ] \ + [ipx::get_hdl_parameters MEM_TYPE -of_objects $cc] + set_property -dict [list \ "value_validation_type" "pairs" \ "value_validation_pairs" { \ @@ -79,42 +144,53 @@ set_property -dict [list \ ] \ [ipx::get_user_parameters TX_OR_RXN_PATH -of_objects $cc] -## MEMC_UIF_DATA_WIDTH set_property -dict [list \ - "value_validation_type" "list" \ - "value_validation_list" "64 128 256 512 1024" \ + "value_validation_type" "pairs" \ + "value" "10" \ + "value_validation_pairs" {\ + "1kB" "10" \ + "2kB" "11" \ + "4kB" "12" \ + "8kB" "13" \ + "16kB" "14" \ + "32kB" "15" \ + "64kB" "16" \ + "128kB" "17" \ + "256kB" "18" \ + "512kB" "19" \ + "1MB" "20" \ + "2MB" "21" \ + "4MB" "22" \ + "8MB" "23" \ + "16MB" "24" \ + "32MB" "25" \ + "64MB" "26" \ + "128MB" "27" \ + "256MB" "28" \ + "512MB" "29" \ + "1GB" "30" \ + "2GB" "31" \ + "4GB" "32" \ + "8GB" "33" \ + "16GB" "34" \ + } \ ] \ - [ipx::get_user_parameters MEMC_UIF_DATA_WIDTH -of_objects $cc] - -## MEMC_UIF_ADDRESS_WIDTH -set_property -dict [list \ - "value_validation_type" "range_long" \ - "value_validation_range_minimum" "8" \ - "value_validation_range_maximum" "31" \ - ] \ - [ipx::get_user_parameters MEMC_UIF_ADDRESS_WIDTH -of_objects $cc] - -## MEM_SIZE - 8GB?? -set_property -dict [list \ - "value_validation_type" "range_long" \ - "value_validation_range_minimum" "2" \ - "value_validation_range_maximum" "8589934592" \ - ] \ - [ipx::get_user_parameters MEM_SIZE -of_objects $cc] + [ipx::get_user_parameters MEM_SIZE_LOG2 -of_objects $cc] ## Boolean parameters foreach {k v} { \ - "SRC_RAW_DATA_EN" "false" \ - "DST_RAW_DATA_EN" "false" \ + "HAS_BYPASS" "true" \ "DST_CYCLIC_EN" "true" \ "SYNC_EXT_ADD_INTERNAL_CDC" "true" \ } { \ set_property -dict [list \ + "value_format" "bool" \ "value_format" "bool" \ "value" $v \ ] \ [ipx::get_user_parameters $k -of_objects $cc] set_property -dict [list \ + "value_format" "bool" \ "value_format" "bool" \ "value" $v \ ] \ @@ -152,34 +228,11 @@ set_property -dict [list \ "display_name" "Storage Type" \ ] [ipgui::get_guiparamspec -name "MEM_TYPE" -component $cc] -ipgui::add_param -name "MEM_SIZE" -component $cc -parent $general_group +ipgui::add_param -name "MEM_SIZE_LOG2" -component $cc -parent $general_group set_property -dict [list \ "display_name" "Storage Size" \ -] [ipgui::get_guiparamspec -name "MEM_SIZE" -component $cc] - -## DDR controller's user interface related configurations -set m_controller_group [ipgui::add_group -name "DDR Controller Interface Configuration" -component $cc \ - -parent $page0 -display_name "DDR Controller Interface Configuration" ] - -ipgui::add_param -name "MEMC_UIF_DATA_WIDTH" -component $cc -parent $m_controller_group -set_property -dict [list \ - "widget" "comboBox" \ - "display_name" "Interface data width" \ -] [ipgui::get_guiparamspec -name "MEMC_UIF_DATA_WIDTH" -component $cc] -set_property enablement_tcl_expr {$MEM_TYPE == 1} [ipx::get_user_parameters MEMC_UIF_DATA_WIDTH -of_objects $cc] - -ipgui::add_param -name "MEMC_UIF_ADDRESS_WIDTH" -component $cc -parent $m_controller_group -set_property -dict [list \ - "widget" "comboBox" \ - "display_name" "Interface address width" \ -] [ipgui::get_guiparamspec -name "MEMC_UIF_ADDRESS_WIDTH" -component $cc] -set_property enablement_tcl_expr {$MEM_TYPE == 1} [ipx::get_user_parameters MEMC_UIF_ADDRESS_WIDTH -of_objects $cc] - -ipgui::add_param -name "MEMC_BADDRESS" -component $cc -parent $m_controller_group -set_property -dict [list \ - "display_name" "PL DDR base address" \ -] [ipgui::get_guiparamspec -name "MEMC_BADDRESS" -component $cc] -set_property enablement_tcl_expr {$MEM_TYPE == 1} [ipx::get_user_parameters MEMC_BADDRESS -of_objects $cc] + "tooltip" "Log2 value of Storage Size in bytes" \ +] [ipgui::get_guiparamspec -name "MEM_SIZE_LOG2" -component $cc] ## Transmit and receive endpoints set source_group [ipgui::add_group -name "Source Endpoint Configuration" -component $cc \ @@ -194,37 +247,19 @@ set_property -dict [list \ "display_name" "Source Interface data width" \ ] [ipgui::get_guiparamspec -name "SRC_DATA_WIDTH" -component $cc] -ipgui::add_param -name "SRC_ADDR_WIDTH" -component $cc -parent $source_group -set_property -dict [list \ - "display_name" "Source Interface address width" \ -] [ipgui::get_guiparamspec -name "SRC_ADDR_WIDTH" -component $cc] - ipgui::add_param -name "DST_DATA_WIDTH" -component $cc -parent $destination_group set_property -dict [list \ "display_name" "Destination Interface data width" \ ] [ipgui::get_guiparamspec -name "DST_DATA_WIDTH" -component $cc] -ipgui::add_param -name "DST_ADDR_WIDTH" -component $cc -parent $destination_group -set_property -dict [list \ - "display_name" "Destination Interface address width" \ -] [ipgui::get_guiparamspec -name "DST_ADDR_WIDTH" -component $cc] - ## Other features set features_group [ipgui::add_group -name "Features" -component $cc \ -parent $page0 -display_name "Features" ] - -ipgui::add_param -name "SRC_RAW_DATA_EN" -component $cc -parent $features_group +ipgui::add_param -name "HAS_BYPASS" -component $cc -parent $features_group set_property -dict [list \ - "display_name" "Source Raw Data Enable" \ -] [ipgui::get_guiparamspec -name "SRC_RAW_DATA_EN" -component $cc] -set_property enablement_tcl_expr {$TX_OR_RXN_PATH == 0} [ipx::get_user_parameters SRC_RAW_DATA_EN -of_objects $cc] - -ipgui::add_param -name "DST_RAW_DATA_EN" -component $cc -parent $features_group -set_property -dict [list \ - "display_name" "Destionation Raw Data Enable" \ -] [ipgui::get_guiparamspec -name "DST_RAW_DATA_EN" -component $cc] -set_property enablement_tcl_expr {$TX_OR_RXN_PATH == 1} [ipx::get_user_parameters DST_RAW_DATA_EN -of_objects $cc] + "display_name" "Internal Bypass Data Path Enabled" \ +] [ipgui::get_guiparamspec -name "HAS_BYPASS" -component $cc] ipgui::add_param -name "DST_CYCLIC_EN" -component $cc -parent $features_group set_property -dict [list \ @@ -241,3 +276,4 @@ set_property -dict [list \ ipx::create_xgui_files $cc ipx::save_core [ipx::current_core] + diff --git a/library/data_offload/data_offload_regmap.v b/library/data_offload/data_offload_regmap.v index fa9471898..9cf46bdcc 100644 --- a/library/data_offload/data_offload_regmap.v +++ b/library/data_offload/data_offload_regmap.v @@ -38,9 +38,11 @@ module data_offload_regmap #( parameter ID = 0, parameter [ 0:0] MEM_TYPE = 1'b0, - parameter [33:0] MEM_SIZE = 1024, + parameter MEM_SIZE_LOG2 = 10, parameter TX_OR_RXN_PATH = 0, - parameter AUTO_BRINGUP = 0) ( + parameter AUTO_BRINGUP = 0, + parameter HAS_BYPASS = 1 +) ( // microprocessor interface input up_clk, @@ -77,14 +79,15 @@ module data_offload_regmap #( output sync, output [ 1:0] sync_config, - output reg [33:0] src_transfer_length, + output [MEM_SIZE_LOG2-1:0] src_transfer_length, + output [MEM_SIZE_LOG2-1:0] dst_transfer_length, // FSM control and status - input [ 1:0] src_fsm_status, - input [ 1:0] dst_fsm_status, + input [ 4:0] src_fsm_status, + input [ 3:0] dst_fsm_status, - input [31:0] sample_count_msb, - input [31:0] sample_count_lsb + input src_overflow, + input dst_underflow ); @@ -93,6 +96,8 @@ module data_offload_regmap #( localparam [31:0] CORE_VERSION = 32'h00010061; // 1.00.a localparam [31:0] CORE_MAGIC = 32'h44414F46; // DAOF + localparam [33:0] MEM_SIZE = 1 << MEM_SIZE_LOG2; + // internal registers reg [31:0] up_scratch = 'd0; @@ -101,18 +106,20 @@ module data_offload_regmap #( reg up_sync = 'd0; reg [ 1:0] up_sync_config = 'd0; reg up_oneshot = 1'b0; - reg [33:0] up_transfer_length = 'd0; + reg [MEM_SIZE_LOG2-1:0] up_transfer_length = 'd0; + reg up_src_overflow = 1'b0; + reg up_dst_underflow = 1'b0; //internal signals wire up_ddr_calib_done_s; - wire [ 1:0] up_wr_fsm_status_s; - wire [ 1:0] up_rd_fsm_status_s; - wire [31:0] up_sample_count_msb_s; - wire [31:0] up_sample_count_lsb_s; + wire [ 4:0] up_wr_fsm_status_s; + wire [ 3:0] up_rd_fsm_status_s; wire src_sw_resetn_s; wire dst_sw_resetn_s; wire [33:0] src_transfer_length_s; + wire up_src_overflow_set_s; + wire up_dst_underflow_set_s; // write interface always @(posedge up_clk) begin @@ -124,34 +131,47 @@ module data_offload_regmap #( up_bypass <= 'd0; up_sync <= 'd0; up_sync_config <= 'd0; - up_transfer_length <= 34'h0; + up_transfer_length <= {MEM_SIZE_LOG2{1'b1}}; + up_src_overflow <= 1'b0; + up_dst_underflow <= 1'b0; end else begin up_wack <= up_wreq; /* Scratch Register */ - if ((up_wreq == 1'b1) && (up_waddr[11:0] == 14'h02)) begin + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h02)) begin up_scratch <= up_wdata; end /* Transfer Length Register */ - if ((up_wreq == 1'b1) && (up_waddr[11:0] == 14'h07)) begin - up_transfer_length <= {up_wdata[27:0], 6'b0}; + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h07)) begin + up_transfer_length <= {up_wdata[MEM_SIZE_LOG2-7:0], {6{1'b1}}}; + end + /* Memory interface status register */ + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h20) && up_wdata[4]) begin + up_src_overflow <= 1'b0; + end else if (up_src_overflow_set_s) begin + up_src_overflow <= 1'b1; + end + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h20) && up_wdata[5]) begin + up_dst_underflow <= 1'b0; + end else if (up_dst_underflow_set_s) begin + up_dst_underflow <= 1'b1; end /* Reset Offload Register */ - if ((up_wreq == 1'b1) && (up_waddr[11:0] == 14'h21)) begin + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h21)) begin up_sw_resetn <= up_wdata[0]; end /* Control Register */ - if ((up_wreq == 1'b1) && (up_waddr[11:0] == 14'h22)) begin + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h22)) begin up_oneshot <= up_wdata[1]; - up_bypass <= up_wdata[0]; + up_bypass <= up_wdata[0] & HAS_BYPASS; end /* SYNC Offload Register - self cleared, one pulse signal */ - if ((up_wreq == 1'b1) && (up_waddr[11:0] == 14'h40)) begin + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h40)) begin up_sync <= up_wdata[0]; end else begin up_sync <= 1'b0; end /* SYNC RX Configuration Register */ - if ((up_wreq == 1'b1) && (up_waddr[11:0] == 14'h41)) begin + if ((up_wreq == 1'b1) && (up_waddr[13:0] == 14'h41)) begin up_sync_config <= up_wdata[1:0]; end end @@ -161,7 +181,7 @@ module data_offload_regmap #( always @(posedge up_clk) begin if (up_rstn == 1'b0) begin up_rack <= 1'b0; - up_rdata <= 14'b0; + up_rdata <= 32'b0; end else begin up_rack <= up_rreq; case(up_raddr) @@ -183,7 +203,8 @@ module data_offload_regmap #( /* Configuration Register */ 14'h004: up_rdata <= { - 30'b0, + 29'b0, + /* 2 */ HAS_BYPASS[0], /* 1 */ TX_OR_RXN_PATH[0], /* 0 */ MEM_TYPE[0] }; @@ -197,13 +218,19 @@ module data_offload_regmap #( }; /* Configuration data transfer length */ - 14'h007: up_rdata <= {4'b0, up_transfer_length[33:6]}; + 14'h007: up_rdata <= { + {32-(MEM_SIZE_LOG2-6){1'b0}}, + up_transfer_length[MEM_SIZE_LOG2-1:6] + }; /* 0x08-0x1f reserved for future use */ /* Memory Physical Interface Status */ 14'h020: up_rdata <= { - 31'b0, + 26'b0, + up_dst_underflow, + up_src_overflow, + 3'b0, /* 0 */ up_ddr_calib_done_s }; /* Reset Offload Register */ @@ -233,17 +260,11 @@ module data_offload_regmap #( /* FMS Debug Register */ 14'h080: up_rdata <= { - 24'b0, - /* 07-06 */ 2'b0, - /* 05-04 */ up_rd_fsm_status_s, - /* 03-02 */ 2'b0, - /* 01-00 */ up_wr_fsm_status_s + 20'b0, + /* 11-08 */ up_rd_fsm_status_s, + 3'b0, + /* 04-00 */ up_wr_fsm_status_s }; - /* Sample Count LSB Register */ - 14'h081: up_rdata <= up_sample_count_lsb_s; - - /* Sample Count MSB Register */ - 14'h082: up_rdata <= up_sample_count_msb_s; default: up_rdata <= 32'h00000000; endcase @@ -253,7 +274,7 @@ module data_offload_regmap #( // Clock Domain Crossing Logic for reset, control and status signals sync_data #( - .NUM_OF_BITS (2), + .NUM_OF_BITS (4), .ASYNC_CLK (1)) i_dst_fsm_status ( .in_clk (dst_clk), @@ -263,7 +284,7 @@ module data_offload_regmap #( ); sync_data #( - .NUM_OF_BITS (2), + .NUM_OF_BITS (5), .ASYNC_CLK (1)) i_src_fsm_status ( .in_clk (src_clk), @@ -272,18 +293,6 @@ module data_offload_regmap #( .out_data (up_wr_fsm_status_s) ); - sync_data #( - .NUM_OF_BITS (64), - .ASYNC_CLK (1)) - i_xfer_status ( - .in_clk (src_clk), - .in_data ({sample_count_msb, - sample_count_lsb}), - .out_clk (up_clk), - .out_data ({up_sample_count_msb_s, - up_sample_count_lsb_s}) - ); - generate if (TX_OR_RXN_PATH) begin : sync_tx_path @@ -357,22 +366,55 @@ module data_offload_regmap #( ); sync_data #( - .NUM_OF_BITS (34), + .NUM_OF_BITS (MEM_SIZE_LOG2), .ASYNC_CLK (1)) i_sync_src_transfer_length ( .in_clk (up_clk), .in_data (up_transfer_length), .out_clk (src_clk), - .out_data (src_transfer_length_s) + .out_data (src_transfer_length) + ); + sync_data #( + .NUM_OF_BITS (MEM_SIZE_LOG2), + .ASYNC_CLK (1)) + i_sync_dst_transfer_length ( + .in_clk (up_clk), + .in_data (up_transfer_length), + .out_clk (dst_clk), + .out_data (dst_transfer_length) ); always @(posedge src_clk) begin src_sw_resetn <= src_sw_resetn_s; - src_transfer_length <= src_transfer_length_s; end always @(posedge dst_clk) begin dst_sw_resetn <= dst_sw_resetn_s; end + generate if (TX_OR_RXN_PATH == 0) begin + sync_event #( + .NUM_OF_EVENTS (1), + .ASYNC_CLK (1)) + i_wr_overflow_sync ( + .in_clk (src_clk), + .in_event (src_overflow), + .out_clk (up_clk), + .out_event (up_src_overflow_set_s) + ); + assign up_dst_underflow_set_s = 1'b0; + end else begin + sync_event #( + .NUM_OF_EVENTS (1), + .ASYNC_CLK (1)) + i_rd_underflow_sync ( + .in_clk (dst_clk), + .in_event (dst_underflow), + .out_clk (up_clk), + .out_event (up_dst_underflow_set_s) + ); + assign up_src_overflow_set_s = 1'b0; + end + endgenerate + endmodule diff --git a/library/data_offload/data_offload_sv.ttcl b/library/data_offload/data_offload_sv.ttcl index 402d9243a..a00bd8a66 100644 --- a/library/data_offload/data_offload_sv.ttcl +++ b/library/data_offload/data_offload_sv.ttcl @@ -5,17 +5,10 @@ <: setFileExtension ".sv" :> <: set id [get_property MODELPARAM_VALUE.ID] :> <: set mem_type [get_property MODELPARAM_VALUE.MEM_TYPE] :> -<: set mem_size [get_property MODELPARAM_VALUE.MEM_SIZE] :> -<: set memc_uif_data_width [get_property MODELPARAM_VALUE.MEMC_UIF_DATA_WIDTH] :> -<: set memc_uif_address_width [get_property MODELPARAM_VALUE.MEMC_UIF_ADDRESS_WIDTH] :> -<: set memc_baddress [get_property MODELPARAM_VALUE.MEMC_BADDRESS] :> +<: set mem_size_log2 [get_property MODELPARAM_VALUE.MEM_SIZE_LOG2] :> <: set tx_or_rxn_path [get_property MODELPARAM_VALUE.TX_OR_RXN_PATH] :> <: set src_data_width [get_property MODELPARAM_VALUE.src_data_width] :> -<: set src_raw_data_en [get_property MODELPARAM_VALUE.src_raw_data_en] :> -<: set src_addr_width [get_property MODELPARAM_VALUE.src_addr_width] :> <: set dst_data_width [get_property MODELPARAM_VALUE.dst_data_width] :> -<: set dst_raw_data_en [get_property MODELPARAM_VALUE.dst_raw_data_en] :> -<: set dst_addr_width [get_property MODELPARAM_VALUE.dst_addr_width] :> <: set dst_cyclic_en [get_property MODELPARAM_VALUE.dst_cyclic_en] :> // boolean to intiger @@ -37,17 +30,10 @@ package <=: ComponentName :>_pkg; parameter <=: ComponentName :>_ID = <=: $id :>; parameter <=: ComponentName :>_MEM_TYPE = <=: $mem_type :>; - parameter <=: ComponentName :>_MEM_SIZE = <=: $mem_size :>; - parameter <=: ComponentName :>_MEMC_UIF_DATA_WIDTH = <=: $memc_uif_data_width :>; - parameter <=: ComponentName :>_MEMC_UIF_ADDRESS_WIDTH = <=: $memc_uif_address_width :>; - parameter <=: ComponentName :>_MEMC_BADDRESS = <=: h2vh $memc_baddress :>; + parameter <=: ComponentName :>_MEM_SIZE_LOG2 = <=: $mem_size_log2 :>; parameter <=: ComponentName :>_TX_OR_RXN_PATH = <=: b2i $tx_or_rxn_path :>; parameter <=: ComponentName :>_SRC_DATA_WIDTH = <=: b2i $src_data_width :>; - parameter <=: ComponentName :>_SRC_RAW_DATA_WIDTH = <=: b2i $src_raw_data_en :>; - parameter <=: ComponentName :>_SRC_ADDR_WIDTH = <=: b2i $src_addr_width :>; parameter <=: ComponentName :>_DST_DATA_WIDTH = <=: b2i $dst_data_width :>; - parameter <=: ComponentName :>_DST_RAW_DATA_WIDTH = <=: b2i $dst_raw_data_en :>; - parameter <=: ComponentName :>_DST_ADDR_WIDTH = <=: b2i $dst_addr_width :>; parameter <=: ComponentName :>_DST_CYCLIC_EN = <=: b2i $dst_cyclic_en :>; ////////////////////////////////////////////////////////////////////////// diff --git a/library/data_offload/docs/generic_bd.svg b/library/data_offload/docs/generic_bd.svg index 0a6df8124..dc10b53b3 100755 --- a/library/data_offload/docs/generic_bd.svg +++ b/library/data_offload/docs/generic_bd.svg @@ -12,7 +12,7 @@ viewBox="0 0 800.00001 500.00001" id="svg2" version="1.1" - inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)" + inkscape:version="0.92.2 (5c3e80d, 2017-08-06)" sodipodi:docname="generic_bd.svg"> @@ -294,17 +294,17 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="306.64583" - inkscape:cy="264.01023" + inkscape:zoom="1.4" + inkscape:cx="316.268" + inkscape:cy="214.56695" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" units="px" inkscape:window-width="1920" - inkscape:window-height="1010" - inkscape:window-x="-7" - inkscape:window-y="-7" + inkscape:window-height="968" + inkscape:window-x="-4" + inkscape:window-y="-4" inkscape:window-maximized="1" inkscape:document-rotation="0" /> AXI_MM SOURCE DESTINATION FIFO_WR + style="font-size:10.66666698px;line-height:0">M_STORAGE_AXIS FIFO_RD + style="font-size:10.66666698px;line-height:1.25">S_STORAGE_AXIS