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
main
Laszlo Nagy 2022-02-24 13:44:05 +02:00 committed by Laszlo Nagy
parent 35d32e0143
commit c3ae609bc8
10 changed files with 631 additions and 945 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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.

View File

@ -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]

View File

@ -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

View File

@ -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 :>;
//////////////////////////////////////////////////////////////////////////

View File

@ -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">
<defs
id="defs4">
@ -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" />
<metadata
@ -428,18 +428,18 @@
style="font-size:15px;line-height:1.25">AXI_MM</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.3333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
x="205.43683"
y="728.12866"
style="font-style:normal;font-weight:normal;font-size:21.33329964px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
x="214.00826"
y="713.12866"
id="text2292"><tspan
sodipodi:role="line"
id="tspan2290"
x="205.43683"
y="728.12866"
x="214.00826"
y="732.00366"
style="text-align:center;text-anchor:middle" /><tspan
sodipodi:role="line"
x="205.43683"
y="754.79529"
x="214.00826"
y="758.67023"
id="tspan2294"
style="text-align:center;text-anchor:middle">SOURCE</tspan></text>
<text
@ -461,18 +461,18 @@
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:21.3333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
x="607.05249"
y="724.40942"
style="font-style:normal;font-weight:normal;font-size:21.33329964px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
x="608.48108"
y="708.69513"
id="text2292-9"><tspan
sodipodi:role="line"
id="tspan2290-3"
x="607.05249"
y="724.40942"
x="608.48108"
y="727.57013"
style="text-align:center;text-anchor:middle" /><tspan
sodipodi:role="line"
x="607.05249"
y="751.07605"
x="608.48108"
y="754.23669"
id="tspan2294-9"
style="text-align:center;text-anchor:middle">DESTINATION</tspan></text>
<path
@ -490,25 +490,25 @@
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="304.78723"
x="298.78723"
y="907.06915"
id="text5814-3"><tspan
sodipodi:role="line"
id="tspan5816-8"
x="304.78723"
x="298.78723"
y="907.06915"
style="font-size:15px;line-height:1.25">FIFO_WR</tspan></text>
style="font-size:10.66666698px;line-height:0">M_STORAGE_AXIS</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="409.59558"
x="407.59558"
y="907.33258"
id="text5814-3-0"><tspan
sodipodi:role="line"
id="tspan5816-8-3"
x="409.59558"
x="407.59558"
y="907.33258"
style="font-size:15px;line-height:1.25">FIFO_RD</tspan></text>
style="font-size:10.66666698px;line-height:1.25">S_STORAGE_AXIS</tspan></text>
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect4733-3-2"

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -5,8 +5,8 @@ proc ad_data_offload_create {instance_name
mem_size
source_dwidth
destination_dwidth
{ddr_data_width 0}
{ddr_addr_width 0}
{axi_data_width 256}
{axi_addr_width 32}
{shared_devclk 0}} {
global ad_hdl_dir
@ -31,7 +31,6 @@ proc ad_data_offload_create {instance_name
create_bd_intf_pin -mode Master -vlnv xilinx.com:interface:axis_rtl:1.0 m_axis
create_bd_pin -dir I init_req
create_bd_pin -dir O init_ack
create_bd_pin -dir I sync_ext
set source_addresses [expr ($mem_size * 8) / $source_dwidth]
@ -44,13 +43,11 @@ proc ad_data_offload_create {instance_name
###########################################################################
ad_ip_instance data_offload i_data_offload [list \
MEM_TYPE $mem_type \
MEM_SIZE $mem_size \
MEM_TYPE [expr $mem_type == 0 ? 0 : 1] \
MEM_SIZE_LOG2 [log2 $mem_size] \
TX_OR_RXN_PATH $datapath_type \
SRC_DATA_WIDTH $source_dwidth \
SRC_ADDR_WIDTH $source_awidth \
DST_DATA_WIDTH $destination_dwidth \
DST_ADDR_WIDTH $destination_awidth \
DST_CYCLIC_EN $datapath_type \
SYNC_EXT_ADD_INTERNAL_CDC [expr {!$shared_devclk}] \
]
@ -60,65 +57,49 @@ proc ad_data_offload_create {instance_name
# Internal storage instance (BRAMs)
###########################################################################
## Add the memory module source into the project file set
if {[get_files -quiet "ad_mem_asym.v"] == ""} {
add_files -norecurse -fileset sources_1 "$ad_hdl_dir/library/common/ad_mem_asym.v"
}
create_bd_cell -type module -reference ad_mem_asym storage_unit
set_property -dict [list \
CONFIG.A_DATA_WIDTH $source_dwidth \
CONFIG.A_ADDRESS_WIDTH $source_awidth \
CONFIG.B_DATA_WIDTH $destination_dwidth \
CONFIG.B_ADDRESS_WIDTH $destination_awidth \
CONFIG.CASCADE_HEIGHT 1 \
] [get_bd_cells storage_unit]
ad_connect storage_unit/clka i_data_offload/s_axis_aclk
ad_connect storage_unit/wea i_data_offload/fifo_src_wen
ad_connect storage_unit/addra i_data_offload/fifo_src_waddr
ad_connect storage_unit/dina i_data_offload/fifo_src_wdata
ad_connect storage_unit/clkb i_data_offload/m_axis_aclk
ad_connect storage_unit/reb i_data_offload/fifo_dst_ren
ad_connect storage_unit/addrb i_data_offload/fifo_dst_raddr
ad_connect storage_unit/doutb i_data_offload/fifo_dst_rdata
ad_connect i_data_offload/fifo_dst_ready VCC ; ## BRAM is always ready
ad_connect i_data_offload/ddr_calib_done VCC
} elseif {$mem_type == 1} {
###########################################################################
# Bridge instance for the external DDR4 memory contreller
# NOTE: The MIG instantiation should be in project's system_bd.tcl file
###########################################################################
ad_ip_instance util_fifo2axi_bridge fifo2axi_bridge [list \
ad_ip_instance util_do_ram storage_unit [list \
SRC_DATA_WIDTH $source_dwidth \
SRC_ADDR_WIDTH $source_awidth \
DST_DATA_WIDTH $destination_dwidth \
DST_ADDR_WIDTH $destination_awidth \
AXI_DATA_WIDTH $ddr_data_width \
AXI_ADDR_WIDTH $ddr_addr_width \
AXI_ADDRESS 0x00000000 \
AXI_ADDRESS_LIMIT [format 0x%X [expr int([expr { pow(2, 30) }]) - 1]] \
REMOVE_NULL_BEAT_EN $datapath_type \
LENGTH_WIDTH [log2 $mem_size] \
]
ad_connect fifo2axi_bridge/fifo_src_clk i_data_offload/s_axis_aclk
ad_connect fifo2axi_bridge/fifo_src_resetn i_data_offload/fifo_src_resetn
ad_connect fifo2axi_bridge/fifo_src_wen i_data_offload/fifo_src_wen
ad_connect fifo2axi_bridge/fifo_src_waddr i_data_offload/fifo_src_waddr
ad_connect fifo2axi_bridge/fifo_src_wdata i_data_offload/fifo_src_wdata
ad_connect fifo2axi_bridge/fifo_src_wlast i_data_offload/fifo_src_wlast
} elseif {$mem_type == 1 || $mem_type == 2} {
###########################################################################
# Bridge instance for the external DDR (1) / HBM(2) memory contreller
# NOTE: The DDR/HBM instantiation should be in project's system_bd.tcl file
###########################################################################
source $ad_hdl_dir/library/util_hbm/scripts/adi_util_hbm.tcl
ad_connect fifo2axi_bridge/fifo_dst_clk i_data_offload/m_axis_aclk
ad_connect fifo2axi_bridge/fifo_dst_resetn i_data_offload/fifo_dst_resetn
ad_connect fifo2axi_bridge/fifo_dst_ren i_data_offload/fifo_dst_ren
ad_connect fifo2axi_bridge/fifo_dst_raddr i_data_offload/fifo_dst_raddr
ad_connect fifo2axi_bridge/fifo_dst_rdata i_data_offload/fifo_dst_rdata
ad_connect fifo2axi_bridge/fifo_dst_ready i_data_offload/fifo_dst_ready
ad_create_util_hbm storage_unit \
$datapath_type \
$source_dwidth \
$destination_dwidth \
$mem_size \
$axi_data_width \
$mem_type
if {$mem_type == 1} {
ad_ip_parameter storage_unit CONFIG.AXI_PROTOCOL 0
} else {
ad_ip_parameter storage_unit CONFIG.AXI_PROTOCOL 1
}
}
###########################################################################
# Connect Storage to Data Offload
###########################################################################
ad_connect storage_unit/wr_ctrl i_data_offload/wr_ctrl
ad_connect storage_unit/rd_ctrl i_data_offload/rd_ctrl
ad_connect storage_unit/s_axis i_data_offload/m_storage_axis
ad_connect storage_unit/m_axis i_data_offload/s_storage_axis
ad_connect storage_unit/s_axis_aclk s_axis_aclk
ad_connect storage_unit/s_axis_aresetn s_axis_aresetn
ad_connect storage_unit/m_axis_aclk m_axis_aclk
ad_connect storage_unit/m_axis_aresetn m_axis_aresetn
###########################################################################
# Internal connections
###########################################################################
@ -135,7 +116,6 @@ proc ad_data_offload_create {instance_name
ad_connect m_axis i_data_offload/m_axis
ad_connect init_req i_data_offload/init_req
ad_connect init_ack i_data_offload/init_ack
ad_connect sync_ext i_data_offload/sync_ext
current_bd_instance /