Typically only one of the character error conditions is true at a time. And
even if multiple errors were present at the same time we'd only want to
count one error per character.
For each character track whether at least one of the monitored error
conditions is true. Then count the number of characters for which at least
one error condition occurred. And finally add that sum to the total numbers
of errors.
This results in a slightly better utilization.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When the link is explicitly disabled through the control interface reset
the error statistics counter.
There is usually little benefit to preserving until after the link has been
disabled. If software is interested in the values it can read them before
disabling the link. Having them reset makes the behavior consistent with
all other internal state of the jesd204 RX peripheral, which is reset when
the link is disabled.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In MM2S applications like video DMA it is useful to mark the end of the stream
with the TLAST.
The change enables the generation of the TLAST on the last beat of the
last row of the 2d transfer.
The index on MSB of addresses was set to 31,
but the width of address in the axi_dmac depends on a parameter.
The mismatch causes issues in the Xilinx simulator which does not extends the
narrower width signal with zeros, instead the wider signal gets 'Z' on its MSBs.
When the address was incremented with the stride it became 'X' due the uninitialized
MSBs.
Vivado recognises .h files as C header files,
the expected extension for Verilog Header is .vh
This causes issues in simulating block designs since these files
won't be exported for the simulation even if they are
part of the simulation fileset.
When creating a block design targeted for simulation, in the testbench
it is useful to know the parameters of the sub components (e.g DMAC)
Xilinx's way to pass the parameters to the testbench in case of it's AXI
verification IP is through package files. We will do the same for the DMAC.
The package file can be generated from template files (ttcl).
These will be added only to the simulation file set of the project and
won't affect synthesis.
This change adds a diagnostic interface to the DMAC core.
The interface exposes internal information about the core,
information which can't be exposed through AXI registers
due the latency and update rate.
Such information is the fullness of the internal buffer.
For this is exposed in bursts and is driven from the destination
clock domain, as this is reflected in its name.
The signal has a fixed size and is dimensioned by
taking in account the supported maximum number of bursts of 128.
This change adds the TLAST signal to the AXI streaming interface
of the source side for Intel targets.
Xilinx based designs already have this since the tlast is part of the
interface definition.
In order to make the signal optional and let the tool connect a
default value to the it, the USE_TLAST_SRC/DEST parameter is
added to the configuration UI. This conditions the tlast port on
the interface of the DMAC.
Xilinx handles the optional signals much better so the parameter
is not required there.
In its current implementation the DMAC requires that the length of a
transfer is aligned to the widest interface. E.g. if the widest interface
is 128 bits wide the length of the transfer needs to be a multiple of 16
bytes.
If the requested length is not aligned to the interface width it will be
rounded up.
This works fine as long as both interfaces have the same width. If they
have different widths it is possible that the length is rounded up to
different values on the source and destination side. In that case the DMA
will deadlock because the transfer lengths don't match and either not enough
of too much data is delivered from the source to the destination side.
Currently it is up to software to make sure that such an invalid
configuration is not possible.
Also enforce this requirement in the DMAC itself by setting the LSBs of the
transfer length to a fixed 1 so that the length is always aligned to the
widest interface.
Software can also use this to discover the length alignment requirement, by
first writing a zero to the length register and then reading the register
back. The LSBs of the read back value will be non-zero indicating the
alignment requirement.
In a similar way the stride needs to be aligned to the width of its
respective interface, so the generated addresses stay aligned. Enforce this
in the same way by keeping the LSBs cleared.
Increment the minor version number to reflect these changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The transfer abort logic in the src_axi_stream module is making some
assumptions about the internal timings of the data mover module.
Move this logic inside the data mover module. This will make it easier to
update the internal logic without having to update other modules.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The only two users of the data mover module both implement the same
sync-transfer-start logic. Move this into the data mover module to avoid
the duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
With the recent rework there is now a fair amount of dead code in the
datamover module that is no longer used. Remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Data is gated on the source side interface and not let into the pipeline if
there is no space available inside the store and forward memory.
This means whenever data is let into the pipeline space is available and
backpressure wont be asserted. Remove the backpressure signals altogether
to simplify the design.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the source side of the DMAC can issue requests for up to
2*FIFO_SIZE-1 bursts even though there is only room for FIFO_SIZE bursts in
the store and forward memory.
This can problematic for memory mapped buses. If the data is not read fast
enough from the DMAC back-pressure will propagate through the whole system
memory subsystem and can cause significant performance penalty or even a
deadlock halting the whole system.
To avoid this make sure that not more that than what fits into the
store-and-forward memory is requested by throttling the request ID based
on how much room is available in the memory.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The second destination side register slice was put in place to provide
additional slack on some of the datapath control signals. It looks as if
this is no longer required for the latest version of the DMA controller.
All timing paths have sufficient margin.
So remove this extra slice register which just takes up resources and adds
pipeline latency.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently both the source side and the destination side interfaces employ a
beat counter to identify the last beat in a burst.
The burst memory already has an internal last signal on the destination
side. Exporting it allows the destination side interfaces to use it instead
of having to generate their own signal. This allows to eliminate the beat
counters on the destination side and simplify the data path logic.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the destination side request ID is synchronized response ID from
the source side. This signal is effectively the same as the synchronized
src ID inside the burst memory. The only difference is that they might not
increment in the exact same clock cycle.
Exporting the request ID from the burst memory means we can remove the extra
synchronizer block.
This has the added bonus that the request ID will increment in the same
clock cycle as when the data becomes available from the memory.
This means we can assume that when there is a outstanding burst request
indicated via the ID that data is available from the memory and vice versa
when data is available from the memory that there is a outstanding burst
request.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the DMAC uses a simple FIFO as the store-and-forward buffer. The
FIFO handshaking is beat based whereas the remainder of the DMAC is burst
based. This means that additional control signals have to be combined with
the FIFO handshaking signal to generate the external handshaking signals.
Re-work the store-and-forward buffer to utilize a BRAM that is subdivided
into N segments. Where N is the maximum number of bursts that can be stored
in the buffer and each segment has the size of the maximum burst length.
Each segment stores the data associated with one burst and even when the
burst is shorter than the maximum burst length the next burst will be
stored in the next segment.
The new store-and-forward buffer takes care of generating all the
handshaking signals. This means handshaking is generated in a central place
and does not have to be combined from multiple data-paths simplifying the
overall logic.
The new store-and-forward buffer also takes care of data width up- and
down-sizing in case that the source and sink modules have a different data
width. This tighter integration will allow future enhancements like using
asymmetric memory.
This re-work lays the foundation of future enhancements to the DMA like
support for un-aligned transfers and early transfer abort which would have
been much more difficult to implement with the previous architecture.
In addition it significantly reduces the resource utilization of the
store-and-forward buffer and allows for better timing due to reduced
combinatorial path lengths.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is an implicit dependency between the outgoing data stream and the
incoming response stream. The AXI specification requires that the
corresponding response is not sent before the last beat of data has been
received.
We can take advantage of this and remove the currently explicit dependency
between the data and response paths. This slightly simplifies the design.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For the AXI streaming interfaces we need to make sure that the handshaking
rules for the external interface are met. Hence we can't just disable the
DMA and have to wait for any pending beats to complete.
For the FIFO interfaces on the other hand no such requirements exist. All
handshaking is for the internal pipeline which will be reset as a whole so
it is OK to violate the handshaking without causing any undefined behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For the memory-mapped AXI read interface the slave asserts rlast for the
last beat in a burst.
This means we don't have to count the number of beats to know when the
burst is completed but instead can use rlast. This slightly reduces the
amount of resources needed for the MM-AXI source module and given that the
beat_counter is often the bottleneck timing wise this should also improve
the timing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When the DMA is disabled it should gracefully shutdown and eventually end
up in an idle state. All outstanding AXI MM requests need to complete
before the DMA is fully disabled.
Add testbenches that test this for both AXI MM read and write behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The DMAC allows a transfer to be aborted. When a transfer is aborted the
DMAC shuts down as fast as possible while still completing any pending
transactions as required by the protocol specifications of the port. E.g.
for AXI-MM this means to complete all outstanding bursts.
Once the DMAC has entered an idle state a special synchronization signal is
send to all modules. This synchronization signal instructs them to flush
the pipeline and remove any stale data and metadata associated with the
aborted transfer. Once all data has been flushed the DMAC enters the
shutdown state and is ready for the next transfer.
In addition each module has a reset that resets the modules state and is
used at system startup to bring them into a consistent state.
Re-work the shutdown process to instead of flushing the pipeline re-use the
startup reset signal also for shutdown.
To manage the reset signal generation introduce the reset manager module.
It contains a state machine that will assert the reset signals in the
correct order and for the appropriate duration in case of a transfer
shutdown.
The reset signal is asserted in all domains until it has been asserted for
at least 4 clock cycles in the slowest domain. This ensures that the reset
signal is not de-asserted in the faster domains before the slower domains
have had a chance to process the reset signal.
In addition the reset signal is de-asserted in the opposite direction of
the data flow. This ensures that the data sink is ready to receive data
before the data source can start sending data. This simplifies the internal
handshaking.
This approach has multiple advantages.
* Issuing a reset and removing all state takes less time than
explicitly flushing one sample per clock cycle at a time.
* It simplifies the logic in the faster clock domains at the expense of
more complicated logic in the slower control clock domain. This allows
for higher fMax on the data paths.
* Less signals to synchronize from the control domain to the data domains
The implementation of the pause mode has also slightly changed. Pause is
now a simple disable of the data domains. When the transfer is resumed
after a pause the data domains are re-enabled and continue at their
previous state.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Move the transfer logic, including the 2d module, into its own sub-module.
This allows testing of the full transfer logic independently of the
register map logic.
The top-level module now only instantiates the register map and transfer
module, but does not have any logic on its own.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The timing exceptions for the debug paths are currently a bit to broad and
can include paths that should not have an exception.
All the debug signals are coming from the i_request_arb instance, so
include that in the match to avoid false positives.
For most projects this wont have been a problem since there is usually a
fair amount of slack on the paths that were affected by this. But in
projects with high utilization this might result in undefined behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Fix the read side of the CDC data FIFO. The read address generation did not
function correctly.
Redesign the read side of the FIFO, and make sure that it becomes empty after
the DMA transfer ends; and never get stock in a cyclic mode.
The dac_last signal is not used anywhere in the module. Remove it and its
synchronization registers.
Fixes the following warnings:
[Synth 8-6014] Unused sequential element dac_dlast_reg was removed. ["axi_dacfifo_rd.v":372]
[Synth 8-6014] Unused sequential element dac_dlast_m1_reg was removed. ["axi_dacfifo_rd.v":373]
[Synth 8-6014] Unused sequential element dac_dlast_m2_reg was removed. ["axi_dacfifo_rd.v":374]
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Commit bfc8ec28c3 ("util_axis_fifo: instantiate block ram in async mode")
added the read-enable (reb) signal to the ad_mem block.
It didn't update the ad_mem instance in axi_dacfifo_address_buffer.v. This
results in the read-enable of the address_buffer being tied to 0.
Fix this by connecting the same signal that increments the read address.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The DMAC implementation guarantees that the expression `dma_valid &
dma_xfer_req` is always identical to just dma_valid.
When generating the util_dacfifo dma_wren_s signal the optimizer doesn't know
of this though and hence will route both signals into the LUT that drives
the write enable for the BRAMs.
Simplify the expression by removing dma_xfer_req from it. Considering this
can be a fairly high fan-out net and is typically the bottleneck for the
util_dacfifo timing this helps to improve the timing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Some parts of the util_cdc library rely on dead logic elimination to remove
unused logic. Unfortunately with newer Vivado versions this results in
warnings about unused sequential elements being removed. Like:
WARNING: [Synth 8-6014] Unused sequential element cdc_sync_stage1_reg was removed.
To avoid this encase the logic in generate blocks that makes sure they are
not generated when not needed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This reverts commit 4b1d9fc86b "axi_dmac: Modified in order to avoid
vivado crash".
Vivado no longer crashes and this structure is much more efficient when it
comes to resource usage and timing. The intention here is to create a 1-bit
memory that is N entries deep and not a N bit signal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The burst_count signal and its derived signals are not used until the
burst_count has been explicitly initialized by loading a transfer. There is
no need to have a reset.
This reduces the fan-out of the reset signal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The data path register of the 2d_transfer module are qualified by the
corresponding valid signal. Their content is not used until they have been
explicitly initialized. There is no need to reset them explicitly.
This reduces the fan-out of the reset signal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is no need to reset the data path in the address generator. The
values of the register on the data path are not used until they have been
explicitly initialized. Removing the reset simplifies the structure and
reduces the fan-out of the reset signal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Xilinx tools don't allow to use $clog2() when computing the value of a
localparam, even though it is valid Verilog.
For this reason a parameter was used for BYTES_PER_BURST_WIDTH so far. But
that generates warnings from both Quartus and Vivado since the parameter is
not part of the parameter list.
Fix this by changing it to a localparam and computing the log2() manually.
The upper limit for the burst length is known to be 4k, so values larger
than that don't have to be supported.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A larger store-and-forward memory provides better protection against worst
case memory interface latencies by being able to store more data before
over-/underflowing.
Based on empirical testing it was found that using a size of 4 bursts can
still result in underflows/overflows under certain conditions. These do not
happen when using a size of 8 bursts.
This change does not significantly increase resource consumption. Both on
Intel and Xilinx the block RAM has a minimum depth of 512 entries. With a
default burst length of 16 beats that allows for up to 32 bursts without
requiring additional block RAM.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The label for the store-and-forward memory size configuration option at the
moment is just "FIFO Size" and while the store-and-forward memory uses a
FIFO that is just a implementation detail.
Change the label to "Store-and-Forward Memory Size". This is more
descriptive as it references the function not the implementation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>