pluto_hdl_adi/library/axi_dmac/address_generator.v

188 lines
6.1 KiB
Coq
Raw Normal View History

// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2014-2023 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
2018-03-14 14:45:47 +00:00
// 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 address_generator #(
parameter ID_WIDTH = 3,
parameter DMA_DATA_WIDTH = 64,
parameter DMA_ADDR_WIDTH = 32,
parameter BEATS_PER_BURST_WIDTH = 4,
parameter BYTES_PER_BEAT_WIDTH = $clog2(DMA_DATA_WIDTH/8),
parameter LENGTH_WIDTH = 8,
parameter CACHE_COHERENT = 0
) (
input clk,
input resetn,
input req_valid,
output reg req_ready,
input [DMA_ADDR_WIDTH-1:BYTES_PER_BEAT_WIDTH] req_address,
output reg [ID_WIDTH-1:0] id,
input [ID_WIDTH-1:0] request_id,
input bl_valid,
output reg bl_ready,
input [BEATS_PER_BURST_WIDTH-1:0] measured_last_burst_length,
input eot,
input enable,
output reg enabled,
input addr_ready,
output reg addr_valid,
output [DMA_ADDR_WIDTH-1:0] addr,
output [LENGTH_WIDTH-1:0] len,
output [ 2:0] size,
output [ 1:0] burst,
output [ 2:0] prot,
output [ 3:0] cache
);
localparam MAX_BEATS_PER_BURST = {1'b1,{BEATS_PER_BURST_WIDTH{1'b0}}};
localparam MAX_LENGTH = {BEATS_PER_BURST_WIDTH{1'b1}};
`include "inc_id.vh"
assign burst = 2'b01;
assign prot = 3'b000;
// If CACHE_COHERENT is set, signal downstream that this transaction must be
// looked up in cache. Otherwise default to "normal non-cachable bufferable".
assign cache = CACHE_COHERENT ? 4'b1110 : 4'b0011;
assign size = DMA_DATA_WIDTH == 1024 ? 3'b111 :
DMA_DATA_WIDTH == 512 ? 3'b110 :
DMA_DATA_WIDTH == 256 ? 3'b101 :
DMA_DATA_WIDTH == 128 ? 3'b100 :
DMA_DATA_WIDTH == 64 ? 3'b011 :
DMA_DATA_WIDTH == 32 ? 3'b010 :
DMA_DATA_WIDTH == 16 ? 3'b001 : 3'b000;
reg [LENGTH_WIDTH-1:0] length = 'h0;
reg [DMA_ADDR_WIDTH-BYTES_PER_BEAT_WIDTH-1:0] address = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] last_burst_len = 'h00;
assign addr = {address, {BYTES_PER_BEAT_WIDTH{1'b0}}};
assign len = length;
reg addr_valid_d1;
reg last = 1'b0;
// If we already asserted addr_valid we have to wait until it is accepted before
// we can disable the address generator.
always @(posedge clk) begin
if (resetn == 1'b0) begin
enabled <= 1'b0;
end else if (enable == 1'b1) begin
enabled <= 1'b1;
end else if (addr_valid == 1'b0) begin
enabled <= 1'b0;
end
end
always @(posedge clk) begin
if (bl_valid == 1'b1 && bl_ready == 1'b1) begin
last_burst_len <= measured_last_burst_length;
end
end
always @(posedge clk) begin
if (addr_valid == 1'b0) begin
last <= eot;
if (eot == 1'b1) begin
length <= last_burst_len;
end else begin
length <= MAX_LENGTH;
end
axi_dmac: Rework transfer shutdown 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>
2017-09-21 14:02:44 +00:00
end
end
always @(posedge clk) begin
if (req_ready == 1'b1) begin
address <= req_address;
end else if (addr_valid == 1'b1 && addr_ready == 1'b1) begin
address <= address + MAX_BEATS_PER_BURST;
end
end
always @(posedge clk) begin
if (resetn == 1'b0) begin
bl_ready <= 1'b1;
end else begin
if (bl_ready == 1'b1) begin
bl_ready <= ~bl_valid;
end else if (addr_valid == 1'b0 && eot == 1'b1) begin
// assert bl_ready only when the addr_valid asserts in the next cycle
if (id != request_id && enable == 1'b1) begin
bl_ready <= 1'b1;
end
end
end
end
always @(posedge clk) begin
if (resetn == 1'b0) begin
req_ready <= 1'b1;
axi_dmac: Rework transfer shutdown 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>
2017-09-21 14:02:44 +00:00
addr_valid <= 1'b0;
end else begin
if (req_ready == 1'b1) begin
req_ready <= ~req_valid;
end else if (addr_valid == 1'b1 && addr_ready == 1'b1) begin
addr_valid <= 1'b0;
req_ready <= last;
end else if (id != request_id && enable == 1'b1) begin
// if eot wait until the last_burst_len gets synced over
if (eot == 1'b0 || (eot == 1'b1 && bl_ready == 1'b0)) begin
addr_valid <= 1'b1;
end
end
end
end
always @(posedge clk) begin
addr_valid_d1 <= addr_valid;
end
always @(posedge clk) begin
if (resetn == 1'b0) begin
id <= 'h0;
end else if (addr_valid == 1'b1 && addr_valid_d1 == 1'b0) begin
id <= inc_id(id);
end
end
endmodule