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