data_offload: Initial commit

main
Istvan Csomortani 2021-03-15 08:50:39 +00:00 committed by Mihaita Nagy
parent 6e97803437
commit 86b611c1f7
10 changed files with 2537 additions and 0 deletions

View File

@ -61,6 +61,7 @@ clean:
$(MAKE) -C cn0363/cn0363_dma_sequencer clean $(MAKE) -C cn0363/cn0363_dma_sequencer clean
$(MAKE) -C cn0363/cn0363_phase_data_sync clean $(MAKE) -C cn0363/cn0363_phase_data_sync clean
$(MAKE) -C cordic_demod clean $(MAKE) -C cordic_demod clean
$(MAKE) -C data_offload clean
$(MAKE) -C intel/adi_jesd204 clean $(MAKE) -C intel/adi_jesd204 clean
$(MAKE) -C intel/avl_adxcfg clean $(MAKE) -C intel/avl_adxcfg clean
$(MAKE) -C intel/avl_adxcvr clean $(MAKE) -C intel/avl_adxcvr clean
@ -177,6 +178,7 @@ lib:
$(MAKE) -C cn0363/cn0363_dma_sequencer $(MAKE) -C cn0363/cn0363_dma_sequencer
$(MAKE) -C cn0363/cn0363_phase_data_sync $(MAKE) -C cn0363/cn0363_phase_data_sync
$(MAKE) -C cordic_demod $(MAKE) -C cordic_demod
$(MAKE) -C data_offload
$(MAKE) -C intel/adi_jesd204 $(MAKE) -C intel/adi_jesd204
$(MAKE) -C intel/avl_adxcfg $(MAKE) -C intel/avl_adxcfg
$(MAKE) -C intel/avl_adxcvr $(MAKE) -C intel/avl_adxcvr

View File

@ -0,0 +1,21 @@
####################################################################################
## Copyright 2018(c) Analog Devices, Inc.
## Auto-generated, do not modify!
####################################################################################
LIBRARY_NAME := data_offload
GENERIC_DEPS += ../common/up_axi.v
GENERIC_DEPS += ../common/ad_mem_asym.v
GENERIC_DEPS += ../common/ad_axis_inf_rx.v
GENERIC_DEPS += data_offload_fsm.v
GENERIC_DEPS += data_offload_regmap.v
GENERIC_DEPS += data_offload.v
XILINX_DEPS += data_offload_constr.ttcl
XILINX_DEPS += data_offload_ip.tcl
XILINX_LIB_DEPS += util_axis_fifo_asym
XILINX_LIB_DEPS += util_cdc
include ../scripts/library.mk

View File

@ -0,0 +1,650 @@
# Data offload IP core
## Description, general use cases
Data offload module for high-speed converters:
**NOTE**: This IP will always have a storage unit (internal or external to the FPGA) and is
designed to handle high data rates. If your data paths will run in a lower data
rate, and your intention is just to transfer the data to another clock domain or
to adjust the bus width of the data path, you must to use another IP.
* in case of DAC, the DMA initialize the storage unit, after that the controller
will push the data to the DAC interface in one-shot or cyclic way, until the next initialization
* in case of ADC, the DMA request a transfer, the controller will save the data into
the storage unit, after that will push it to the DMA
* BYPASS mode: simple streaming FIFO in case of clock rate or data width differences
between source and sink interfaces (data rate MUST match in order to work); the BYPASS
mode is used when an initially high rate path is downgraded to lower rates.
## Table of content
* [Block diagrams](README.md#block-diagram)
* [Parameters](README.md#parameters)
* [Interfaces](README.md#interfaces)
* [Register map](README.md#register-map)
* [Clock tree](README.md#clock-tree)
* [Data path](README.md#data-path)
* [Control path](README.md#control-path-offload-fsm)
## Generic arhitecture
The main role of our data paths, is to stream data from point A to point B
in a particular system. There are always a SOURCE and a DESTINATION
point, which can be a device (ADC or DAC), a DMA (for system memory) or any other
data processing IP.
In the context of Data Offload IP, we don't need to know who is the source and
who is the destination. Both interface is a AXI4 Stream interface, which can be
supported in both Xilinx's an Intel's architecture, and can be connected to any device
core or DMA.
The storage unit is connected to the Data Offload controller via two FIFO interface.
This way the same controller can be used for various storage solutions. (BRAM,
URAM, external memory etc.)
## Block diagram
![Generic Block Diagram](./docs/do_arch.svg)
## Parameters
| NAME | TYPE | DEFAULT | DESCRIPTION |
|----------------------|:-----------:|:----------:|:---------------------------:|
|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 |
|RX_ENABLE | [ 0:0] | 1 | Enable/disable the ADC path |
|RX_FRONTEND_IF | [ 0:0] | 0 | M_AXIS - 0; FIFO_RD - 1 (FRONTEND is the DMA side) |
|RX_BACKEND_IF | [ 0:0] | 0 | S_AXIS - 0; FIFO_WR - 1 (BACKEND is the device side) |
|RX_FRONTEND_DATA_WIDTH| integer | 64 | The data width of the RX frontend interface, it depends of the dma configuration |
|RX_BACKEND_DATA_WIDTH | integer | 64 | The data width of the RX backend interface, it depends of the device core configuration |
|RX_RAW_DATA_EN | [ 0:0] | 1 | Enables a gearbox module in the RX path, so only the raw samples will be stored in the memory. |
|TX_ENABLE | [ 0:0] | 1 | Enable/disable the DAC path |
|TX_FRONTEND_IF | [ 0:0] | 0 | S_AXIS - 0; FIFO_WR - 1 (FRONTEND is the DMA side) |
|TX_BACKEND_IF | [ 0:0] | 0 | M_AXIS - 0; FIFO_RD - 1 (BACKEND is the device side) |
|TX_FRONTEND_DATA_WIDTH| integer | 64 | The data width of the TX frontend interface, it depends of the dma configuration |
|TX_BACKEND_DATA_WIDTH | integer | 64 | The data width of the TX backend interface, it depends of the device core configuration |
|TX_RAW_DATA_EN | [ 0:0] | 1 | Enables a gearbox module in the TX path, so only the raw samples will be stored in the memory. |
|MEMC_UIF_TYPE | [ 0:0] | 0 | AXI_MM - 0; AVL_MM - 1 |
|MEMC_UIF_DATA_WIDTH | [ 0:0] | 512 | The valid data depends on the DDRx memory controller IP. |
|MEMC_UIF_ADDRESS_WIDTH| integer | 25 | The valid data depends on the DDRx memory controller IP. |
|MEMC_RX_BADDRESS | [31:0] |32'h000000 | DDR base address for the ADC data. |
|MEMC_TX_BADDRESS | [31:0] |32'h100000 | DDR base address for the DAC data. |
## Interfaces
![Interfaces](../../docs/block_diagrams/data_offload/interface.svg)
### AXI4 Lite Memory Mapped Slave (S_AXI4_LITE)
This interface is used to access the register map.
```verilog
// interface clock -- system clock -- 100 MHz
input s_axi_aclk
// interface resetn -- synchronous reset active low
input s_axi_aresetn
/* write address channel */
// validates the address on the bus
input s_axi_awvalid
// write address
input [15:0] s_axi_awaddr
// protection type -- not used in the core
input [ 2:0] s_axi_awprot
// write ready, indicates that the slave can accept the address
output s_axi_awready
/* write data channel */
// validate the data on the bus
input s_axi_wvalid
// write data
input [31:0] s_axi_wdata
// write strobe, indicates which byte lanes to update
input [ 3:0] s_axi_wstrb
// write ready, indicates that the slave can accept the data
output s_axi_wready
/* write response channel */
// validates the write response of the slave
output s_axi_bvalid
// write response, indicate the status of the transfer
output [ 1:0] s_axi_bresp
// response ready, indicates that the master can accept the data
input s_axi_bready
/* read address channel */
// validates the address on the bus
input s_axi_arvalid
// read address
input [15:0] s_axi_araddr
// protection type -- not used in the core
input [ 2:0] s_axi_arprot
// read ready, indicates that the slave can accept the address
output s_axi_arready
/* read data channel */
// validate the data on the bus
output s_axi_rvalid
// read response, indicate the status of the transfer
output [ 1:0] s_axi_rresp
// read data drivers by the slave
output [31:0] s_axi_rdata
// read ready, indicates that the master can accept the data
input s_axi_rready
```
### Supported data interfaces
**NOTE**: All the data interfaces for the streams should be supported by both
frontend (DMA) and backend (device) side. Although in general the FIFO_RD and
FIFO_WR interfaces can be found in the device side, and the AXIS interfaces on
the DMA side.
#### AXI4 Stream interface (S_AXIS | M_AXIS)
* The AXI Stream Slave (S_AXIS) interface is used to receive AXI stream from
the transmit DMA or ADC device.
* The AXI Stream Master (M_AXIS) interface is used to transmit AXI stream
to receive DMA or DAC device
**NOTE**: In all cases the data stream is controlled by the device. Although the
generic AXI Stream interface standard supports back-pressure, in our cases none
the DAC, nore the ADC can wait for data. The DMA always have to be ready, samples
will be lost otherwise!
```verilog
// NOTE: this reference is a master interface
// interface clock -- can be device/core clock or DMA clock
input m_axis_aclk
// interface resetn -- synchronous reset with the system clock
input m_axis_resetn
// indicates that the slave can accept a transfer in the current cycle (in case of an ADC core, this will control the stream)
input m_axis_ready
// indicates that the master is driving a valid transfer
output m_axis_valid
// primary payload
output [DATA_WIDTH-1:0] m_axis_data
// indicates the boundary of a packet
output m_axis_last
// byte qualifier, we need this so we can have different DMA and device data widths
output [(DATA_WIDTH/8)-1:0] m_axis_tkeep
```
**NOTE**: A packet will always be a full buffer. All the data beats going to be
full beats (all the bytes of the bus are valid), except the last one. **axis_last**
and **axis_tkeep** will be used to indicate a partial last beat. This information
should be transferred from the source domain to the sink domain, so we can read
back the data from memory correctly.
#### ADI FIFO interface
This is non-blocking (no back-pressure) interface for the device cores.
To understand the motivation behind the name, let's look at a simple FIFO and its
interfaces:
![Simple FIFO](../../docs/block_diagrams/data_offload/simple_fifo.svg)
A FIFO in general has a **write** and a **read** interface. In each case the
interface is controlled by an external logic. Meaning that the FIFO will always
act as slave. The only difference between the two interfaces is that in case of
the **write** interface the data is driven by the master (we are writing into
the FIFO), and in case of the **read** interface the data is driven by the slave
(we are reading from the FIFO).
To adapt this concept in our case, the device, which can be an ADC or a DAC,
will always be the master. This means, that an ADC core will have a **fifo write**
interface, and a DAC core will have a **fifo read** interface.
In the same time, this means, that a processing core, which wants to interface
a device core, need to have a **salve fifo write** or a **slave fifo read**
interface, in other words needs to act as a FIFO.
**Note:** The processing core (or DMA) can have an AXI stream interface too. To
connect an AXIS stream interface to a FIFO interface the following mapping should
be respected:
* **fifo write to AXIS slave**:
```verilog
// the processing unit should always be READY, otherwise will lose data
assign s_axis_valid = fifo_wr_valid;
assign s_axis_data = fifo_wr_data;
```
* **fifo read to AXIS master**:
```verilog
// the processing unit should drive the data bus with the next valid data,
// as the READY gets asserted
assign m_axis_ready = fifo_rd_valid;
assign fifo_rd_data = m_axis_data;
```
User should be aware that in this case the AXI stream interface will loose the
back pressure capability. The processing unit should be designed to compensate this
scarcity.
**NOTE**: the data stream should arrive in packed format to the core. The core
does not care about number of channels or samples per beat. Result of this
constraint is that the FIFO interface of the **Data Offload** module does not
have any **enable** signals.
```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
```
```verilog
// This is a Slave FIFO Write interface
// device digital interface clock, or core clock
input fifo_wr_clk
// enables the channel -- in our case this is redundant -- maybe we do neet to use it at all
input fifo_wr_enable
// validates the data on the bus, it's driven by the device, indicates when the core drives the bus with new data
input fifo_wr_valid
// primary payload, its data width is equal with the channel's data width
input [DATA_WIDTH-1:0] fifo_wr_data
// indicates an overflow, the sink (offload FIFO in this case) can not consume the data fast enough
output fifo_wr_ovf
```
#### AXI4 Memory Mapped master (M_AXI_MM)
An AXI4 Memory Mapped interface, which transfer data into/from the external DDRx
memory. This interface will be used explicitly with Xilinx FPGAs, to interface
the MC (Memory Controller).
```verilog
/* clocks and resets */
// clock signal of the interface, this is an independent clock from the sys_cpu, in general 200 MHz
input axi_clk
// synchronous active low reset
input axi_resetn
/* write address channel */
// validates the address on the bus
output axi_awvalid
// write address ID, this signal is the identification tag for the write address group of signals
output [ 3:0] axi_awid
// burst type, this must use INCR (incrementing address burst) -- 2'b01
output [ 1:0] axi_awburst
// lock type, atomic characteristics of the transfer -- must be set to 1'b0
output axi_awlock
// indicates the bufferable, cacheable, write-through, write-back, and allocate attributes -- 4'b0011 recommended by Xilinx, IP as slaves in general ignores
output [ 3:0] axi_awcache
// protection type -- not used in the core, recommended value 3'b000
output [ 2:0] axi_awprot
// not implemented in Xilinx Endpoint IP
output [ 3:0] axi_awqos
// not implemented in Xilinx Endpoint IP
output [ 3:0] axi_awuser
// up to 256 beats for incrementing (INCR)
output [ 7:0] axi_awlen
// transfer width 8 to 1024 supported, in general the MIG core has 512 bits interface
output [ 2:0] axi_awsize
// write address
output [ 31:0] axi_awaddr
// write ready, indicates that the slave can accept the address
input axi_awready
/* write data channel */
// validate the data on the bus
output axi_wvalid
// write data
output [AXI_DATA_WIDTH-1:0] axi_wdata
/8)-1:0] axi_wstrb // write strobe, indicates which byte lanes to update
output [(AXI_DATA_WIDTH
// fully supported, this signal indicates the last transfer in a write burst
output axi_wlast
// not implemented in Xilinx Endpoint IP
output [ 3:0] axi_wuser
// write ready, indicates that the slave can accept the data
input axi_wready
/* write response channel */
// validates the write response of the slave
input axi_bvalid
// the identification tag of the write response, the BID value must match the AWID
input [ 3:0] axi_bid
// write response, indicate the status of the transfer
input [ 1:0] axi_bresp
// not implemented in Xilinx Endpoint IP
input [ 3:0] axi_buser
// response ready, indicates that the master can accept the data
output axi_bready
/* read address channel */
// validates the address on the bus
output axi_arvalid
// read address ID, this signal is the identification tag for the read address group of signals
output [ 3:0] axi_arid
// burst type, this must use INCR (incrementing address burst) -- 2'b01
output [ 1:0] axi_arburst
// lock type, atomic characteristics of the transfer -- must be set to 1'b0
output axi_arlock
// indicates the bufferable, cacheable, write-through, write-back, and allocate attributes -- 4'b0011 recommended by Xilinx, IP as slaves in general ignores
output [ 3:0] axi_arcache
// protection type -- not used in the core
output [ 2:0] axi_arprot
// not implemented in Xilinx Endpoint IP
output [ 3:0] axi_arqos
// not implemented in Xilinx Endpoint IP
output [ 3:0] axi_aruser
// up to 256 beats for incrementing (INCR)
output [ 7:0] axi_arlen
// transfer width 8 to 1024 supported, in general the MIG core has 512 bits interface
output [ 2:0] axi_arsize
// read address
output [ 31:0] axi_araddr
// read ready, indicates that the slave can accept the address
input axi_arready
/* read data channel */
// validate the data on the bus
input axi_rvalid
// the RID is generated by the slave and must match by the ARID value
input [ 3:0] axi_rid
// not implemented in Xilinx Endpoint IP
input [ 3:0] axi_ruser
// read response, indicate the status of the transfer
input [ 1:0] axi_rresp
// indicates the last transfer in a read burst
input axi_rlast
// read data drivers by the slave
input [AXI_DATA_WIDTH-1:0] axi_rdata
// read ready, indicates that the master can accept the data
output axi_rready
```
### Avalon Memory Mapped master (AVL_MM)
An Avalon Memory Mapped interface which transfer data into/from an external DDR4
memory. This interface will be used explicitly with Intel FPGAs.
```verilog
// interface clock and reset
input avl_clk
input avl_reset
// address for read or write
output reg [(AVL_ADDRESS_WIDTH-1):0] avl_address
// indicate the number of transfers in each burst
output reg [ 6:0] avl_burstcount
// enables specific byte lanes during transfers on interfaces fo width greater than 8 bits [3]
output reg [ 63:0] avl_byteenable
// asserted to indicate a read transfer (request)
output avl_read
// read data, driven from the slave to the master
input [(AVL_DATA_WIDTH-1):0] avl_readdata
// used for variable-latency, pipelined read transfers, to validate the data on the bus
input avl_readdata_valid
// or waitrequest_n in specs, indicates the availability of the slave
input avl_ready
// asserted to indicate a write transfer
output avl_write
// write data, driven from the master to the slave
output [(AVL_DATA_WIDTH-1):0] avl_writedata
```
### Initialization request interface
Define a simple request/acknowledge 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.
* DAC: As the DMA will send a valid last, the FSM will start to send the
stored data to the device.
* **HARDWARE**
* ADC and DAC: An external signal will trigger the write or read into or from
the memory.
* **NOTE**: In case of DAC, if the DMA does not sent all the data into the
buffer, before a hardware sync event, the unsent data will be ignored. It's the
user/software responsibility to sync up these events accordingly.
* **SOFTWARE**
* The software write a RW1C register which will trigger the reads or writes
into or from the memory.
## Register Map
| WORD | BYTE | BITS | NAME | CLK_DOMAIN | TYPE | DESCRIPTION |
|-------:|:--------:|:--------:|:-------------------:|:----------:|:-----:|:-----------------------:|
| 0x0000 | 0x0000 | | VERSION | SYS | RO | Version number |
| | | [31:16] | MAJOR | | | |
| | | [15: 8] | MINOR | | | |
| | | [ 7: 0] | PATCH | | | |
| 0x0001 | 0x0004 | | PERIPHERAL_ID | SYS | RO | Value of the IP configuration parameter |
| 0x0002 | 0x0008 | | SCRATCH | SYS | RW | Scratch register |
| 0x0003 | 0x000C | | IDENTIFICATION | SYS | RO | Peripheral identification. Default value: 0x44414F46 - ('D','A','O','F') |
| 0x0004 | 0x0010 | | CONFIGURATION | SYS | RO | Core configuration registers |
| | | [ 2: 2] | MEMORY_TYPE | | | The used storage type (embedded or external) |
| | | [ 1: 1] | TX_PATH | | | TX path synthesized/implemented |
| | | [ 0: 0] | RX_PATH | SYS | | RX path synthesized/implemented |
| 0x0005 | 0x0014 | | CONFIG_RX_SIZE_LSB | SYS | RO | 32bits LSB of the receive memory size register |
| 0x0006 | 0x0018 | | CONFIG_RX_SIZE_MSB | SYS | RO | 2bits MSB of the receive memory size register |
| | | [ 1: 0] | RX_SIZE_MSB | SYS | | |
| 0x0007 | 0x001C | | CONFIG_TX_SIZE_LSB | SYS | RO | 32bits LSB of the transmit memory size register |
| 0x0008 | 0x0020 | | CONFIG_TX_SIZE_MSB | SYS | RO | 2bits MSB of the transmit memory size register |
| | | [ 1: 0] | TX_SIZE_MSB | SYS | | |
| 0x0020 | 0x0080 | | MEM_PHY_STATE | DDR | RO | Status bits of the memory controller IP |
| | | [ 0: 0] | CALIB_COMPLETE | | | Indicates that the memory initialization and calibration have completed successfully |
| 0x0021 | 0x0084 | | RESET_OFFLOAD | ALL | RW | Reset all the internal address registers and state machines |
| | | [ 1: 1] | RESET_TX | | | |
| | | [ 0: 0] | RESET_RX | | | |
| 0x0022 | 0x0088 | | RX_CONTROL_REG | RX/RX_DMA | RW | A global control register |
| | | [ 0: 0] | OFFLOAD_BYPASS | | | Bypass the offload storage, the data path consist just of a CDC FIFO |
| 0x0023 | 0x008C | | TX_CONTROL_REG | TX/TX_DMA | RW | A global control register |
| | | [ 1: 1] | ONESHOT_EN | | | By default the TX path runs on CYCLIC mode, set this bit to switch it to ONE-SHOT mode |
| | | [ 0: 0] | OFFLOAD_BYPASS | | | Bypass the offload storage, the data path consist just of a CDC FIFO |
| 0x0040 | 0x0100 | | SYNC_OFFLOAD | | RW1P | Synchronization setup for RX and TX path |
| | | [ 1: 1] | TX_SYNC | TX | | Synchronize the TX data transfer |
| | | [ 0: 0] | RX_SYNC | RX | | Synchronize the RX data capture |
| 0x0041 | 0x0104 | | SYNC_RX_CONFIG | | RW | Synchronization setup for RX path |
| | | [ 1: 0] | SYNC_CONFIG | RX | | Auto - '0'; hardware - '1'; software - '2' |
| 0x0042 | 0x0108 | | SYNC_TX_CONFIG | | RW | Synchronization setup for TX path
| | | [ 1: 0] | SYNC_CONFIG | TX | | Auto - '0'; hardware - '1'; software - '2' |
| 0x0080 | 0x0200 | | RX_FSM_DBG | RX_DMA | RW | Debug register for the RX offload FSM |
| | | [15: 8] | CONTROL_FSM | | | Force the offload state machine into a required state |
| | | [ 7: 0] | FSM_STATE | | | The current state of the offload state machine |
| 0x0081 | 0x0204 | | TX_FSM_DBG | TX_DMA | RW | Debug register for the TX offload FSM |
| | | [16:16] | NO_TLAST | | | This bits gets asserted, if the memory is empty and the DMA trying to read out data |
| | | [15: 8] | CONTROL_FSM | | | Force the offload state machine into a required state |
| | | [ 7: 0] | FSM_STATE | | | The current state of the offload state machine |
| 0x0082 | 0x0204 | | RX_SAMPLE_COUNT_LSB | RX_DMA | RO | Stored sample count for the RX path (32 LSB) |
| 0x0083 | 0x0208 | | RX_SAMPLE_COUNT_MSB | RX_DMA | RO | Stored sample count for the RX path (32 MSB) |
| 0x0084 | 0x020C | | TX_SAMPLE_COUNT_LSB | TX_DMA | RO | Stored sample count for the TX path (32 LSB) |
| 0x0085 | 0x0210 | | TX_SAMPLE_COUNT_MSB | TX_DMA | RO | Stored sample count for the TX path (32 MSB) |
## Clock tree
In general there are at least two different clock in the data offload module:
* DMA or system clock : on this clock will run all the front end interfaces
* Memory Controller user clock : user interface clock of the DDRx controller (**optional**)
* Device clock : the digital interface clock of the converter
![Clocks](../../docs/block_diagrams/data_offload/clocks.svg)
A general frequency relationship of the above clocks are:
```
CLKdma <= CLKddr <= CLKconverter
```
The clock domain crossing should be handled by the [util_axis_fifo](https://github.com/analogdevicesinc/hdl/tree/master/library/util_axis_fifo) module.
* **TODO** : Make sure that we support both AXIS and FIFO
* **TODO** : Add support for asymmetric aspect ratio.
All the back end paths (device side) are time critical. The module must read or
write from or into the storage at the speed of the device.
```
DDR data rate >= Device data rate
DDR data rate >= ADC data rate + DAC data rate
```
## Data path
![Data path](../../docs/block_diagrams/data_offload/datapath.svg)
* The data path should be designed to support any kind of difference between
the source, memory and sink data width.
* The data width adjustments will be made by the CDC_FIFO.
* In both path (ADC and DAC) the data stream at the front-end side is packatized,
meaning there is a valid TLAS/TKEEP in the stream. While in the back-end side
the stream is continuous. (no TLAST/TKEEP)
* The DAC path have to have a depacketizer to get rid of the last partial beat
from the stream.
* Because the ADC path already arrive in a packed form, and we always will
fill up the whole storage, we don't need to treat special use-cases.
### Used storage elements
| | ZC706 | ZCU102 | A10SOC |
|:----------------------|:------------------:|:-----------------:|:----------------:|
| FPGA | XC7Z045 FFG900 2 | XCZU9EG-2FFVB1156 | 10AS066N3F40E2SG |
| External Memory Type | DDR3 SODIMM | DDR4 | DDR4 HILO |
| External Memory Size | 1 GB | 512 MB | 2 GB |
| Embedded Memory Type | BRAM | BRAM | M20K |
| Embedded Memory Size | 19.1 Mb | 32.1 Mb | 41 Mb |
### Data width manipulation
* data width differences should be treated by the CDC FIFO
* the smallest granularity should be 8 bits. This constraints mainly will generate
additional logic just in the TX path, taking the fact that the data from the ADC
will come packed.
* the gearbox main role is to improve the DDR's bandwidth, strips the padding bits
of each samples, so the raw data could be stored into the memory.
### Xilinx's MIG vs. Intel's EMIF
* Incrementing burst support for 1 to 256 beats, the length of the burst should
be defined by the internal controller
* Concurrent read/write access, the external memory to be shared between an ADC
and DAC
* Dynamic burst length tuning: an FSM reads and writes dummy data until both
ADC's overflow and DAC's underflow lines are de-asserted. Pre-requisites : both
device's interface should be up and running.
* **TODO**: prefetch the next transfer if it's possible, by driving the address channels ahead (e.g. Overlapping read burst in case of AXI4)
* Optional gearbox to congest the samples in order to increase the maximum data rate.
* In general we packing all samples into 16 bits. This can add a significant
overhand to the maximum real data rate on the memory interface. The gearbox main
role is to pack and unpack the device's samples into the required data width. (in general 512 or 1024 bit)
Boards with FPGA side DDR3/4 SODIMMs/HILO: ZC706, ZCU102, A10SOC
| | ZC706 | ZCU102 | A10SOC |
|------------------------------|:---------:|:----------:|:----------:|
| Max data throughputs (MT/s) | 1600 | 2666 | 2133 |
| DDRx reference clocks | 200 MHz | 300 MHz | 133 MHz |
| DDRx Data bus width | 64 | 16 | 64 |
| Memory to FPGA clock ratio | 4:1 | 4:1 | 4:1 |
| UI type & burst length | AXI4-256 | AXI4-256 | Avalon Memory Map |
| UI data width | 512 | 512 | 512 |
### Internal cyclic buffer support for the TX path
![Data path with external storage](../../docs/block_diagrams/data_offload/architecture_DDR.svg)
* On the front end side if the TX path, a special buffer will handle the data
width up/down conversions and run in cyclic mode if the length of the data set
is smaller than 4/8 AXI/Avalon burst. This way we can avoid to overload the memory
interface with small bursts.
* On the back end side, because the smallest granularity can be 8 bytes, we need
a dynamic 'depackatizer' or re-aligner, which will filter out the invalid data
bytes from the data stream. (this module will use the tlast and tkeep signal of
the AXI stream interface)
## Control path - Offload FSM
### RX control FSM for internal RAM mode
![RX_control FMS for internal RAM mode](../../docs/block_diagrams/data_offload/rx_bram_fsm.svg)
### TX control FSM for internal RAM mode
![TX_control FMS for internal RAM mode](../../docs/block_diagrams/data_offload/tx_bram_fsm.svg)
**TODO** FSMs for the external DDR mode
## References
### AMBA AXI
* [AMBA specification](http://infocenter.arm.com/help/topic/com.arm.doc.set.amba/index.html#specs)
* [UG761 AXI Reference Guide](https://www.xilinx.com/support/documentation/ip_documentation/ug761_axi_reference_guide.pdf)
### Avalon
* [Avalon Interface Specification](https://www.altera.com/en_US/pdfs/literature/manual/mnl_avalon_spec.pdf)
### Xilinx
* [Device Memory Interface Solutions](https://www.xilinx.com/support/documentation/ip_documentation/mig_7series/v4_2/ds176_7Series_MIS.pdf)
* [Device Memory Interface Solutions User Guide](https://www.xilinx.com/support/documentation/ip_documentation/mig_7series/v4_2/ug586_7Series_MIS.pdf)
* [Ultrascale Architecutre-Based FPGAs Memory IP (v1.4)](https://www.xilinx.com/support/documentation/ip_documentation/ultrascale_memory_ip/v1_4/pg150-ultrascale-memory-ip.pdf)
* [Xilinx FIFO Generator](https://www.xilinx.com/products/intellectual-property/fifo_generator.html#documentation)
* [7 Series FPGAs Memory Resources](https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf)
* [Ultrascale Memory Resources](https://www.xilinx.com/support/documentation/user_guides/ug573-ultrascale-memory-resources.pdf)
### Intel
* [Intel Arria 10 Core Fabric and General Purpose I/Os Handbook](https://www.altera.com/en_US/pdfs/literature/hb/arria-10/a10_handbook.pdf)
* [Intel Arria 10 External Memory Interface IP User Guide](https://www.altera.com/en_US/pdfs/literature/ug/ug-20115.pdf)
* [Intel Arria 10 External Memory Interface IP Design Example](https://www.altera.com/en_US/pdfs/literature/ug/ug-20118.pdf)
* [Intel SCFIFO and DCFIFO](https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_fifo.pdf)
* [Intel Startix 10 High-Performance Design Handbook](https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/hb/stratix-10/s10_hp_hb.pdf)
* [Intel Stratix 10 Embedded Memory User Guide](https://www.altera.com/en_US/pdfs/literature/hb/stratix-10/ug-s10-memory.pdf)
### Supported FPGA boards
* [ZC706](https://www.xilinx.com/products/boards-and-kits/ek-z7-zc706-g.html)
* [ZCU102](https://www.xilinx.com/products/boards-and-kits/ek-u1-zcu102-g.html)
* [A10SOC](https://www.altera.com/products/boards_and_kits/dev-kits/altera/arria-10-soc-development-kit.html)

View File

@ -0,0 +1,413 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2018 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns / 1ps
module data_offload #(
parameter ID = 0,
parameter [ 0:0] MEM_TYPE = 1'b0, // 1'b0 -FPGA RAM; 1'b1 - external memory
parameter [31:0] MEM_SIZE = 1023, // 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 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) (
// AXI4 Slave for configuration
input s_axi_aclk,
input s_axi_aresetn,
input s_axi_awvalid,
input [15:0] s_axi_awaddr,
input [ 2:0] s_axi_awprot,
output s_axi_awready,
input s_axi_wvalid,
input [31:0] s_axi_wdata,
input [ 3:0] s_axi_wstrb,
output s_axi_wready,
output s_axi_bvalid,
output [ 1:0] s_axi_bresp,
input s_axi_bready,
input s_axi_arvalid,
input [15:0] s_axi_araddr,
input [ 2:0] s_axi_arprot,
output s_axi_arready,
output s_axi_rvalid,
input s_axi_rready,
output [ 1:0] s_axi_rresp,
output [31:0] s_axi_rdata,
// AXI4 stream slave for source stream (TX_DMA or ADC) -- Source interface
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,
input s_axis_last,
input [SRC_DATA_WIDTH/8-1:0] s_axis_tkeep,
// AXI4 stream master for destination stream (RX_DMA or DAC) -- Destination
// interface
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,
output m_axis_last,
output [DST_DATA_WIDTH/8-1:0] m_axis_tkeep,
// initialization request interface
input init_req,
output init_ack,
input sync_ext,
// FIFO interface - Memory UI
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,
output fifo_dst_ren,
output fifo_dst_resetn,
output [DST_ADDR_WIDTH-1:0] fifo_dst_raddr,
input [DST_DATA_WIDTH-1:0] fifo_dst_rdata,
output fifo_dst_rlast,
input fifo_dst_ready,
// Status and monitor
input ddr_calib_done
);
// local parameters -- to make the code more readable
localparam SRC_ADDR_WIDTH_BYPASS = (SRC_DATA_WIDTH > DST_DATA_WIDTH) ? 3 : 3 + $clog2(SRC_DATA_WIDTH/DST_DATA_WIDTH);
localparam DST_ADDR_WIDTH_BYPASS = (SRC_DATA_WIDTH <= DST_DATA_WIDTH) ? 3 + $clog2(DST_DATA_WIDTH/SRC_DATA_WIDTH) : 3;
localparam SRC_BEAT_BYTE = $clog2(SRC_DATA_WIDTH/8);
// NOTE: Clock domain prefixes
// src_* - AXI4 Stream Slave interface's clock domain
// dst_* - AXI4 Stream Master interface's clock domain
// internal signals
wire up_clk;
wire up_rstn;
wire up_wreq_s;
wire [13:0] up_waddr_s;
wire [31:0] up_wdata_s;
wire up_rreq_s;
wire [13:0] up_raddr_s;
wire up_wack_s;
wire up_rack_s;
wire [31:0] up_rdata_s;
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_last_s;
wire dst_mem_valid_s;
wire dst_mem_valid_int_s;
wire m_axis_reset_int_s;
wire [31:0] src_transfer_length_s;
wire src_wr_last_int_s;
wire [31:0] src_wr_last_beat_s;
assign src_clk = s_axis_aclk;
assign dst_clk = m_axis_aclk;
// internal registers
reg [31: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;
assign fifo_dst_rlast = dst_mem_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))
i_data_offload_fsm (
.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),
.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 (dst_mem_last_s),
.rd_tkeep (m_axis_tkeep),
.rd_oneshot (oneshot_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)
);
// 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 fifo_dst_ready_int_s = fifo_dst_ready;
assign dst_mem_valid_int_s = dst_mem_valid_s & m_axis_ready;
end else begin
assign fifo_dst_ready_int_s = 1'b1;
// 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 fifo_src_wdata = s_axis_data;
assign fifo_dst_ren = dst_mem_valid_s;
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 (dst_mem_last_s),
.inf_valid (m_axis_valid_s),
.inf_last (m_axis_last_s),
.inf_data (m_axis_data_s),
.inf_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
// it's supported just with the FIFO interface
util_axis_fifo_asym #(
.S_DATA_WIDTH (SRC_DATA_WIDTH),
.S_ADDRESS_WIDTH (SRC_ADDR_WIDTH_BYPASS),
.M_DATA_WIDTH (DST_DATA_WIDTH),
.ASYNC_CLK (1))
i_bypass_fifo (
.m_axis_aclk (m_axis_aclk),
.m_axis_aresetn (dst_rstn),
.m_axis_ready (m_axis_ready),
.m_axis_valid (valid_bypass_s),
.m_axis_data (data_bypass_s),
.m_axis_tlast (),
.m_axis_empty (),
.m_axis_almost_empty (),
.s_axis_aclk (s_axis_aclk),
.s_axis_aresetn (src_rstn),
.s_axis_ready (ready_bypass_s),
.s_axis_valid (s_axis_valid),
.s_axis_data (s_axis_data),
.s_axis_tlast (),
.s_axis_full (),
.s_axis_almost_full ()
);
// register map
data_offload_regmap #(
.ID (ID),
.MEM_TYPE (MEM_TYPE),
.MEM_SIZE (MEM_SIZE),
.TX_OR_RXN_PATH (TX_OR_RXN_PATH),
.AUTO_BRINGUP (AUTO_BRINGUP))
i_regmap (
.up_clk (up_clk),
.up_rstn (up_rstn),
.up_rreq (up_rreq_s),
.up_rack (up_rack_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata_s),
.up_wreq (up_wreq_s),
.up_wack (up_wack_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.src_clk (s_axis_aclk),
.dst_clk (m_axis_aclk),
.src_sw_resetn (src_rstn),
.dst_sw_resetn (dst_rstn),
.ddr_calib_done (ddr_calib_done),
.src_bypass (src_bypass_s),
.dst_bypass (dst_bypass_s),
.oneshot (oneshot_s),
.sync (sync_int_s),
.sync_config (sync_config_s),
.src_transfer_length (src_transfer_length_s),
.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])
);
// axi interface wrapper
assign up_clk = s_axi_aclk;
assign up_rstn = s_axi_aresetn;
up_axi #(
.AXI_ADDRESS_WIDTH (16))
i_up_axi (
.up_rstn (up_rstn),
.up_clk (up_clk),
.up_axi_awvalid (s_axi_awvalid),
.up_axi_awaddr (s_axi_awaddr),
.up_axi_awready (s_axi_awready),
.up_axi_wvalid (s_axi_wvalid),
.up_axi_wdata (s_axi_wdata),
.up_axi_wstrb (s_axi_wstrb),
.up_axi_wready (s_axi_wready),
.up_axi_bvalid (s_axi_bvalid),
.up_axi_bresp (s_axi_bresp),
.up_axi_bready (s_axi_bready),
.up_axi_arvalid (s_axi_arvalid),
.up_axi_araddr (s_axi_araddr),
.up_axi_arready (s_axi_arready),
.up_axi_rvalid (s_axi_rvalid),
.up_axi_rresp (s_axi_rresp),
.up_axi_rdata (s_axi_rdata),
.up_axi_rready (s_axi_rready),
.up_wreq (up_wreq_s),
.up_waddr (up_waddr_s),
.up_wdata (up_wdata_s),
.up_wack (up_wack_s),
.up_rreq (up_rreq_s),
.up_raddr (up_raddr_s),
.up_rdata (up_rdata_s),
.up_rack (up_rack_s));
/* 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.
*
*/
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
end
// transfer length is in bytes, but counter monitors the source data beats
assign src_wr_last_beat_s = (src_transfer_length_s == 32'h0) ? MEM_SIZE[31:SRC_BEAT_BYTE] : src_transfer_length_s[31:SRC_BEAT_BYTE];
assign src_wr_last_int_s = (src_data_counter == src_wr_last_beat_s) ? 1'b1 : 1'b0;
endmodule

View File

@ -0,0 +1,177 @@
<: set ComponentName [getComponentNameString] :>
<: setOutputDirectory "./" :>
<: setFileName [ttcl_add $ComponentName "_constr"] :>
<: setFileExtension ".xdc" :>
<: setFileProcessingOrder late :>
<: set mem_type [getBooleanValue "MEM_TYPE"] :>
<: set tx_enable [getBooleanValue "TX_OR_RXN_PATH"] :>
## for all synchronization registers from util_cdc modules
set_property ASYNC_REG TRUE \
[get_cells -hier {*cdc_sync_stage1_reg*}] \
[get_cells -hier {*cdc_sync_stage2_reg*}]
## For RX in case of BRAMs
<: if { $tx_enable == 0 } { :>
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_wr_sync/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 } { :>
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_rd_sync/cdc_sync_stage1_reg[*]/D}]
<: 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 } { :>
set_false_path \
-from [get_cells -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/cdc_hold_reg[*]}] \
-to [get_cells -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/out_data_reg[*]}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/in_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/i_sync_out/cdc_sync_stage1_reg[*]/D}]
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}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_ddr_calib_done_sync/cdc_sync_stage1_reg[0]/D}]
<: } :>
## 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}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_dst_fsm_status/out_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_dst_fsm_status/i_sync_in/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-from [get_cells -hierarchical * -filter {NAME=~*/i_dst_fsm_status/cdc_hold_reg[*]}] \
-to [get_cells -hierarchical * -filter {NAME=~*/i_dst_fsm_status/out_data_reg[*]}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_src_fsm_status/in_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_src_fsm_status/i_sync_out/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_src_fsm_status/out_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_src_fsm_status/i_sync_in/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-from [get_cells -hierarchical * -filter {NAME=~*/i_src_fsm_status/cdc_hold_reg[*]}] \
-to [get_cells -hierarchical * -filter {NAME=~*/i_src_fsm_status/out_data_reg[*]}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_wr_empty_sync/in_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_wr_empty_sync/i_sync_out/cdc_sync_stage1_reg[*]/D}]
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}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*i_sync_xfer_control/out_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*i_sync_xfer_control/i_sync_in/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-from [get_cells -hierarchical * -filter {NAME=~*i_sync_xfer_control/cdc_hold_reg[*]}] \
-to [get_cells -hierarchical * -filter {NAME=~*i_sync_xfer_control/out_data_reg[*]}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_rd_init_req_sync/cdc_sync_stage1_reg[*]/D}]
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_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}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_dst_xfer_control/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_dst_oneshot_sync/cdc_sync_stage1_reg[0]/D}]
## Constraints for the bypass module
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}]

View File

@ -0,0 +1,44 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2019 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns / 1ps
module data_offload_control #(
) (
);
endmodule

View File

@ -0,0 +1,565 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2018 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
/* This module controls the read and write access to the storage unit. It is
* used for bot transmit and receive use cases
*/
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)(
// 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,
// 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 reg 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)
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
);
// 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 RD_IDLE = 2'b00;
localparam RD_SYNC = 2'b01;
localparam RD_READ_FROM_MEM = 2'b11;
// Synchronization options
localparam AUTOMATIC = 2'b00;
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;
// internal signals
wire wr_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_internal_s;
wire rd_sync_internal_s;
wire wr_sync_external_s;
wire rd_sync_external_s;
(* DONT_TOUCH = "TRUE" *) reg [1:0] wr_fsm_state = 2'b00;
(* DONT_TOUCH = "TRUE" *) reg [1:0] rd_fsm_state = 2'b00;
// 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_pos_s) begin
wr_fsm_state <= (TX_OR_RXN_PATH) ? WR_WRITE_TO_MEM : WR_SYNC;
end else begin
wr_fsm_state <= WR_IDLE;
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 (wr_sync_internal_s) begin
wr_fsm_state <= WR_WRITE_TO_MEM;
end
end
default: begin
wr_fsm_state <= WR_WRITE_TO_MEM;
end
endcase
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_init_req_pos_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_full = (wr_addr == {WR_ADDRESS_WIDTH{1'b1}}) ? 1'b1 : 1'b0;
// 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
end
always @(posedge wr_clk) begin
if (wr_resetn_in == 1'b0) begin
wr_last_addr <= {WR_ADDRESS_WIDTH{1'b1}};
end else begin
wr_last_addr <= (wr_last && wr_valid_out) ? wr_addr : wr_last_addr;
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
// write control
assign wr_ready = (wr_fsm_state != WR_WRITE_TO_MEM) ? 1'b0 : 1'b1;
assign wr_valid_out = wr_ready & 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 ((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;
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 (rd_sync_internal_s) 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_oneshot && rd_ready && rd_last) || (rd_init_req_neg_s)) begin
rd_fsm_state <= RD_IDLE;
end else begin
rd_fsm_state <= RD_READ_FROM_MEM;
end
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
assign rd_reading_s = (rd_fsm_state == RD_READ_FROM_MEM) ? 1'b1 : 1'b0;
always @(posedge rd_clk) begin
if (rd_fsm_state != RD_READ_FROM_MEM) begin
rd_addr <= 'b0;
end else begin
if (rd_ready && 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;
always @(posedge rd_clk) begin
if (rd_resetn_in == 1'b0) begin
rd_last <= 1'b0;
rd_isempty <= 1'b0;
end else begin
rd_isempty <= rd_empty_s;
if (rd_empty_s & ~rd_isempty) begin
// in CYCLIC mode rd_last stays low
rd_last <= rd_oneshot;
end else if (rd_last & rd_ready & rd_valid)begin
rd_last <= 1'b0;
end
end
end
always @(posedge rd_clk) begin
if (rd_resetn_in == 1'b0) begin
rd_valid <= 1'b0;
end else begin
if ((rd_ready) && (rd_fsm_state == RD_READ_FROM_MEM)) begin
rd_valid <= 1'b1;
end else begin
rd_valid <= 1'b0;
end
end
end
// CDC circuits
sync_event #(
.NUM_OF_EVENTS (1),
.ASYNC_CLK (1))
i_wr_empty_sync (
.in_clk (rd_clk),
.in_event (rd_isempty),
.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_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_out)),
.out_clk (rd_clk),
.out_event (rd_wr_last_s)
);
sync_bits #(
.NUM_OF_BITS (1),
.ASYNC_CLK (1))
i_rd_init_req_sync (
.in_bits (init_req),
.out_clk (rd_clk),
.out_resetn (1'b1),
.out_bits (rd_init_req_s)
);
sync_bits #(
.NUM_OF_BITS (1),
.ASYNC_CLK (1))
i_wr_init_req_sync (
.in_bits (init_req),
.out_clk (wr_clk),
.out_resetn (1'b1),
.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
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_sync_wr_sync (
.in_bits ({ sync_internal, sync_external }),
.out_clk (wr_clk),
.out_resetn (1'b1),
.out_bits ({ wr_sync_internal_s, wr_sync_external_s })
);
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_sync_rd_sync (
.in_bits ({ sync_internal, sync_external }),
.out_clk (rd_clk),
.out_resetn (1'b1),
.out_bits ({ rd_sync_internal_s, rd_sync_external_s })
);
endmodule

View File

@ -0,0 +1,235 @@
source ../scripts/adi_env.tcl
source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl
adi_ip_create data_offload
adi_ip_files data_offload [list \
"data_offload_sv.ttcl" \
"$ad_hdl_dir/library/common/up_axi.v" \
"$ad_hdl_dir/library/common/ad_mem_asym.v" \
"$ad_hdl_dir/library/common/ad_axis_inf_rx.v" \
"data_offload_regmap.v" \
"data_offload_fsm.v" \
"data_offload.v" ]
## NOTE: To solve the issue AR# 70646 we need to call the following command
##set_property source_mgmt_mode DisplayOnly [current_project]
adi_ip_properties data_offload
adi_ip_ttcl data_offload "data_offload_constr.ttcl"
adi_ip_sim_ttcl data_offload "data_offload_sv.ttcl"
adi_ip_add_core_dependencies { \
analog.com:user:util_cdc:1.0 \
analog.com:user:util_axis_fifo_asym:1.0 \
}
set_property display_name "ADI Data Offload Controller" [ipx::current_core]
set_property description "ADI Data Offload Controller" [ipx::current_core]
## Interface definitions
## destination interfaces (e.g. RX_DMA or DAC core)
adi_add_bus "m_axis" "master" \
"xilinx.com:interface:axis_rtl:1.0" \
"xilinx.com:interface:axis:1.0" \
[ list \
{"m_axis_ready" "TREADY"} \
{"m_axis_valid" "TVALID"} \
{"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)
adi_add_bus "s_axis" "slave" \
"xilinx.com:interface:axis_rtl:1.0" \
"xilinx.com:interface:axis:1.0" \
[ list \
{"s_axis_ready" "TREADY"} \
{"s_axis_valid" "TVALID"} \
{"s_axis_data" "TDATA"} \
{"s_axis_last" "TLAST"} \
{"s_axis_tkeep" "TKEEP"} ]
adi_add_bus_clock "s_axis_aclk" "s_axis" "s_axis_aresetn"
set cc [ipx::current_core]
## Parameter validations
## MEM_TPYE
set_property -dict [list \
"value_validation_type" "pairs" \
"value_validation_pairs" { \
"Internal memory" "0" \
"External memory" "1" \
} \
] \
[ipx::get_user_parameters MEM_TYPE -of_objects $cc]
set_property -dict [list \
"value_validation_type" "pairs" \
"value_validation_pairs" { \
"RX path" "0" \
"TX path" "1" \
} \
] \
[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" \
] \
[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]
## Boolean parameters
foreach {k v} { \
"SRC_RAW_DATA_EN" "false" \
"DST_RAW_DATA_EN" "false" \
"DST_CYCLIC_EN" "true" \
} { \
set_property -dict [list \
"value_format" "bool" \
"value" $v \
] \
[ipx::get_user_parameters $k -of_objects $cc]
set_property -dict [list \
"value_format" "bool" \
"value" $v \
] \
[ipx::get_hdl_parameters $k -of_objects $cc]
}
### Customize IP Layout
## Remove the automatically generated GUI page
ipgui::remove_page -component $cc [ipgui::get_pagespec -name "Page 0" -component $cc]
ipx::save_core [ipx::current_core]
## Create a new GUI page
ipgui::add_page -name {Data Offload} -component [ipx::current_core] -display_name {Data Offload}
set page0 [ipgui::get_pagespec -name "Data Offload" -component $cc]
## General Configurations
set general_group [ipgui::add_group -name "General Configuration" -component $cc \
-parent $page0 -display_name "General Configuration" ]
ipgui::add_param -name "ID" -component $cc -parent $general_group
set_property -dict [list \
"display_name" "Core ID" \
] [ipgui::get_guiparamspec -name "ID" -component $cc]
ipgui::add_param -name "TX_OR_RXN_PATH" -component $cc -parent $general_group
set_property -dict [list \
"widget" "comboBox" \
"display_name" "Data path type" \
] [ipgui::get_guiparamspec -name "TX_OR_RXN_PATH" -component $cc]
ipgui::add_param -name "MEM_TYPE" -component $cc -parent $general_group
set_property -dict [list \
"widget" "comboBox" \
"display_name" "Storage Type" \
] [ipgui::get_guiparamspec -name "MEM_TYPE" -component $cc]
ipgui::add_param -name "MEM_SIZE" -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]
## Transmit and receive endpoints
set source_group [ipgui::add_group -name "Source Endpoint Configuration" -component $cc \
-parent $page0 -display_name "Source Endpoint Configuration" \
-layout "horizontal"]
set destination_group [ipgui::add_group -name "Destination Endpoint Configuration" -component $cc \
-parent $page0 -display_name "Destination Endpoint Configuration" \
-layout "horizontal"]
ipgui::add_param -name "SRC_DATA_WIDTH" -component $cc -parent $source_group
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
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]
ipgui::add_param -name "DST_CYCLIC_EN" -component $cc -parent $features_group
set_property -dict [list \
"display_name" "Destination Cyclic Mode Enabled" \
] [ipgui::get_guiparamspec -name "DST_CYCLIC_EN" -component $cc]
set_property enablement_tcl_expr {$TX_OR_RXN_PATH == 1} [ipx::get_user_parameters DST_CYCLIC_EN -of_objects $cc]
## Create and save the XGUI file
ipx::create_xgui_files $cc
ipx::save_core [ipx::current_core]

View File

@ -0,0 +1,375 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2018 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module data_offload_regmap #(
parameter ID = 0,
parameter [ 0:0] MEM_TYPE = 1'b0,
parameter [33:0] MEM_SIZE = 1024,
parameter TX_OR_RXN_PATH = 0,
parameter AUTO_BRINGUP = 0) (
// microprocessor interface
input up_clk,
input up_rstn,
input up_rreq,
output reg up_rack,
input [13:0] up_raddr,
output reg [31:0] up_rdata,
input up_wreq,
output reg up_wack,
input [13:0] up_waddr,
input [31:0] up_wdata,
// source clock domain
input src_clk,
// destination clock domain
input dst_clk,
// resets for all clock domains
output reg src_sw_resetn,
output reg dst_sw_resetn,
// status bit from the memory controller
input ddr_calib_done,
// bypass control
output src_bypass,
output dst_bypass,
output oneshot,
// synchronization
output sync,
output [ 1:0] sync_config,
output [31:0] src_transfer_length,
// FSM control and status
input [ 1:0] src_fsm_status,
input [ 1:0] dst_fsm_status,
input [31:0] sample_count_msb,
input [31:0] sample_count_lsb
);
// local parameters
localparam [31:0] CORE_VERSION = 32'h00000100; // 0.01.0
localparam [31:0] CORE_MAGIC = 32'h44414F46; // DAOF
// internal registers
reg [31:0] up_scratch = 'd0;
reg up_sw_resetn = 'd0;
reg up_bypass = 'd0;
reg up_sync = 'd0;
reg [ 1:0] up_sync_config = 'd0;
reg up_oneshot = 1'b0;
reg [31:0] up_transfer_length = 'd0;
//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 src_sw_resetn_s;
wire dst_sw_resetn_s;
// write interface
always @(posedge up_clk) begin
if (up_rstn == 1'b0) begin
up_wack <= up_wreq;
up_scratch <= 'd0;
up_sw_resetn <= AUTO_BRINGUP;
up_oneshot <= ~TX_OR_RXN_PATH;
up_bypass <= 'd0;
up_sync <= 'd0;
up_sync_config <= 'd0;
up_transfer_length <= 32'h0;
end else begin
up_wack <= up_wreq;
/* Scratch Register */
if ((up_wreq == 1'b1) && (up_waddr[11: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;
end
/* Reset Offload Register */
if ((up_wreq == 1'b1) && (up_waddr[11: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
up_oneshot <= up_wdata[1];
up_bypass <= up_wdata[0];
end
/* SYNC Offload Register - self cleared, one pulse signal */
if ((up_wreq == 1'b1) && (up_waddr[11: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
up_sync_config <= up_wdata[1:0];
end
end
end
//read interface for common registers
always @(posedge up_clk) begin
if (up_rstn == 1'b0) begin
up_rack <= 1'b0;
up_rdata <= 14'b0;
end else begin
up_rack <= up_rreq;
case(up_raddr)
/* Version Register */
14'h000: up_rdata <= {
CORE_VERSION[31:16], /* MAJOR */
CORE_VERSION[15: 8], /* MINOR */
CORE_VERSION[ 7: 0] /* PATCH */
};
/* Peripheral ID Register */
14'h001: up_rdata <= ID;
/* Peripheral ID Register */
14'h002: up_rdata <= up_scratch;
/* Identification Register */
14'h003: up_rdata <= CORE_MAGIC;
/* Configuration Register */
14'h004: up_rdata <= {
31'b0,
/* 0 */ MEM_TYPE
};
/* Configuration Storage Unit Size LSB Register */
14'h005: up_rdata <= MEM_SIZE[31:0];
/* Configuration Storage Unit Size MSB Register */
14'h006: up_rdata <= {
29'b0,
/* 00-01 */ MEM_SIZE[33:32]
};
/* Configuration data transfer length */
14'h007: up_rdata <= up_transfer_length;
/* 0x08-0x1f reserved for future use */
/* Memory Physical Interface Status */
14'h020: up_rdata <= {
31'b0,
/* 0 */ up_ddr_calib_done_s
};
/* Reset Offload Register */
14'h021: up_rdata <= {
31'b0,
/* 0 */ up_sw_resetn
};
/* Control Register */
14'h022: up_rdata <= {
30'b0,
/* 1 */ up_oneshot,
/* 0 */ up_bypass
};
/* 0x24-0x3f reserved for future use */
/* SYNC Offload Register */
14'h040: up_rdata <= {
31'b0,
/* 0 */ up_sync
};
/* SYNC RX Configuration Register */
14'h041: up_rdata <= {
30'b0,
/* 00-01 */ up_sync_config
};
/* 0x42-0x7f reserved for future use */
/* FMS Debug Register */
14'h080: up_rdata <= {
16'b0,
/* 07-06 */ 2'b0,
/* 05-04 */ up_rd_fsm_status_s,
/* 03-02 */ 2'b0,
/* 01-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
end
end /* read interface */
// Clock Domain Crossing Logic for reset, control and status signals
sync_data #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_dst_fsm_status (
.in_clk (dst_clk),
.in_data (dst_fsm_status),
.out_clk (up_clk),
.out_data (up_rd_fsm_status_s)
);
sync_data #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_src_fsm_status (
.in_clk (src_clk),
.in_data (src_fsm_status),
.out_clk (up_clk),
.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
sync_data #(
.NUM_OF_BITS (3),
.ASYNC_CLK (1))
i_sync_xfer_control (
.in_clk (up_clk),
.in_data ({up_sync_config,
up_sync}),
.out_clk (dst_clk),
.out_data ({sync_config,
sync})
);
end else begin : sync_rx_path
sync_data #(
.NUM_OF_BITS (3),
.ASYNC_CLK (1))
i_sync_xfer_control (
.in_clk (up_clk),
.in_data ({up_sync_config,
up_sync}),
.out_clk (src_clk),
.out_data ({sync_config,
sync})
);
end
endgenerate
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_src_xfer_control (
.in_bits ({ up_sw_resetn, up_bypass }),
.out_clk (src_clk),
.out_resetn (1'b1),
.out_bits ({ src_sw_resetn_s, src_bypass })
);
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
i_dst_xfer_control (
.in_bits ({ up_sw_resetn, up_bypass }),
.out_clk (dst_clk),
.out_resetn (1'b1),
.out_bits ({ dst_sw_resetn_s, dst_bypass })
);
sync_bits #(
.NUM_OF_BITS (1),
.ASYNC_CLK (1))
i_ddr_calib_done_sync (
.in_bits (ddr_calib_done),
.out_clk (up_clk),
.out_resetn (1'b1),
.out_bits (up_ddr_calib_done_s)
);
sync_bits #(
.NUM_OF_BITS (1),
.ASYNC_CLK (1))
i_dst_oneshot_sync (
.in_bits (up_oneshot),
.out_clk (dst_clk),
.out_resetn (1'b1),
.out_bits (oneshot)
);
sync_data #(
.NUM_OF_BITS (32),
.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)
);
always @(posedge src_clk) begin
src_sw_resetn <= src_sw_resetn_s;
end
always @(posedge dst_clk) begin
dst_sw_resetn <= dst_sw_resetn_s;
end
endmodule

View File

@ -0,0 +1,55 @@
<: :>
<: set ComponentName [getComponentNameString] :>
<: setOutputDirectory "./sim/" :>
<: setFileName ${ComponentName}_pkg :>
<: 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 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
<: proc b2i {b} { if {$b==true} {return 1} else {return 0}} :>
// C hex to verilog hex
<: proc h2vh {a} { return [string replace $a 0 1 "'h"]} :>
///////////////////////////////////////////////////////////////////////////
//NOTE: This file has been automatically generated by Vivado.
///////////////////////////////////////////////////////////////////////////
package <=: ComponentName :>_pkg;
///////////////////////////////////////////////////////////////////////////
// These parameters are named after the component for use in your verification
// environment.
///////////////////////////////////////////////////////////////////////////
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 :>_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 :>;
//////////////////////////////////////////////////////////////////////////
endpackage : <=: ComponentName :>_pkg