aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi
diff options
context:
space:
mode:
authorWade Fife <wade.fife@ettus.com>2020-04-06 16:19:50 -0500
committerAaron Rossetto <aaron.rossetto@ni.com>2020-08-04 15:40:08 -0500
commit6d92a1828121ca4b57d496bbf522820f961244b9 (patch)
treef0659ab6d1a6e1f8801db356e2237388d90724f2 /fpga/usrp3/lib/axi
parent24f8bb39fd2769ff93d11b21152a834500152de4 (diff)
downloaduhd-6d92a1828121ca4b57d496bbf522820f961244b9.tar.gz
uhd-6d92a1828121ca4b57d496bbf522820f961244b9.tar.bz2
uhd-6d92a1828121ca4b57d496bbf522820f961244b9.zip
fpga: rfnoc: Add RFNoC Replay block
Diffstat (limited to 'fpga/usrp3/lib/axi')
-rw-r--r--fpga/usrp3/lib/axi/Makefile.srcs1
-rw-r--r--fpga/usrp3/lib/axi/axi_replay.v867
2 files changed, 0 insertions, 868 deletions
diff --git a/fpga/usrp3/lib/axi/Makefile.srcs b/fpga/usrp3/lib/axi/Makefile.srcs
index 598af9ef3..c56244987 100644
--- a/fpga/usrp3/lib/axi/Makefile.srcs
+++ b/fpga/usrp3/lib/axi/Makefile.srcs
@@ -14,7 +14,6 @@ axi_chdr_test_pattern.v \
axi_defs.v \
axi_dma_fifo.v \
axi_dma_master.v \
-axi_replay.v \
axi_embed_tlast.v \
axi_extract_tlast.v \
axi_fast_extract_tlast.v \
diff --git a/fpga/usrp3/lib/axi/axi_replay.v b/fpga/usrp3/lib/axi/axi_replay.v
deleted file mode 100644
index 49e4318c5..000000000
--- a/fpga/usrp3/lib/axi/axi_replay.v
+++ /dev/null
@@ -1,867 +0,0 @@
-//
-// Copyright 2017 Ettus Research, A National Instruments Company
-//
-// SPDX-License-Identifier: LGPL-3.0
-//
-// Module: axi_replay.v
-// Description:
-//
-// This block implements the state machine and control logic for recording and
-// playback of AXI-Stream data, using a DMA-accessible memory as a buffer.
-
-
-module axi_replay #(
- parameter DATA_WIDTH = 64,
- parameter ADDR_WIDTH = 32, // Byte address width used by DMA master
- parameter COUNT_WIDTH = 8 // Length of counters used to connect to the DMA
- // master's read and write interfaces.
-) (
- input wire clk,
- input wire rst, // Synchronous to clk
-
- //---------------------------------------------------------------------------
- // Settings Bus
- //---------------------------------------------------------------------------
-
- input wire set_stb,
- input wire [ 7:0] set_addr,
- input wire [31:0] set_data,
- output reg [31:0] rb_data,
- input wire [ 7:0] rb_addr,
-
- //---------------------------------------------------------------------------
- // AXI Stream Interface
- //---------------------------------------------------------------------------
-
- // Input
- input wire [DATA_WIDTH-1:0] i_tdata,
- input wire i_tvalid,
- input wire i_tlast,
- output wire i_tready,
-
- // Output
- output wire [DATA_WIDTH-1:0] o_tdata,
- output wire o_tvalid,
- output wire o_tlast,
- input wire o_tready,
-
- //---------------------------------------------------------------------------
- // DMA Interface
- //---------------------------------------------------------------------------
-
- // Write interface
- output reg [ ADDR_WIDTH-1:0] write_addr, // Byte address for start of write
- // transaction (64-bit aligned).
- output reg [COUNT_WIDTH-1:0] write_count, // Count of 64-bit words to write, minus 1.
- output reg write_ctrl_valid,
- input wire write_ctrl_ready,
- output wire [ DATA_WIDTH-1:0] write_data,
- output wire write_data_valid,
- input wire write_data_ready,
-
- // Read interface
- output reg [ ADDR_WIDTH-1:0] read_addr, // Byte address for start of read
- // transaction (64-bit aligned).
- output reg [COUNT_WIDTH-1:0] read_count, // Count of 64-bit words to read, minus 1.
- output reg read_ctrl_valid,
- input wire read_ctrl_ready,
- input wire [ DATA_WIDTH-1:0] read_data,
- input wire read_data_valid,
- output wire read_data_ready
-);
-
- //---------------------------------------------------------------------------
- // Constants
- //---------------------------------------------------------------------------
-
- // Size constants
- localparam CMD_WIDTH = 32; // Command width
- localparam LINES_WIDTH = 28; // Width of cmd_num_lines
- localparam WORD_SIZE = DATA_WIDTH/8; // Size of DATA_WIDTH in bytes
-
- // Register offsets
- localparam [7:0] SR_REC_BASE_ADDR = 128;
- localparam [7:0] SR_REC_BUFFER_SIZE = 129;
- localparam [7:0] SR_REC_RESTART = 130;
- localparam [7:0] SR_REC_FULLNESS = 131;
- localparam [7:0] SR_PLAY_BASE_ADDR = 132;
- localparam [7:0] SR_PLAY_BUFFER_SIZE = 133;
- localparam [7:0] SR_RX_CTRL_COMMAND = 152; // Same offset as radio
- localparam [7:0] SR_RX_CTRL_HALT = 155; // Same offset as radio
- localparam [7:0] SR_RX_CTRL_MAXLEN = 156; // Same offset as radio
-
-
- // Memory buffering parameters:
- //
- // Log base 2 of the depth of the input and output FIFOs to use. The FIFOs
- // should be large enough to store more than a complete burst
- // (MEM_BURST_SIZE). A size of 9 (512 64-bit words) is one 36-kbit BRAM.
- localparam REC_FIFO_ADDR_WIDTH = 9; // Log2 of input/record FIFO size
- localparam PLAY_FIFO_ADDR_WIDTH = 9; // Log2 of output/playback FIFO size
- //
- // Amount of data to buffer before writing to RAM. This should be a power of
- // two so that it evenly divides the AXI_ALIGNMENT requirement. It also must
- // not exceed 2**COUNT_WIDTH (the maximum count allowed by DMA master).
- localparam MEM_BURST_SIZE = 2**COUNT_WIDTH; // Size in DATA_WIDTH-sized words
- //
- // AXI alignment requirement (4096 bytes) in DATA_WIDTH-bit words
- localparam AXI_ALIGNMENT = 4096 / WORD_SIZE;
- //
- // Clock cycles to wait before writing something less than MEM_BURST_SIZE
- // to memory.
- localparam DATA_WAIT_TIMEOUT = 31;
-
-
- //---------------------------------------------------------------------------
- // Signals
- //---------------------------------------------------------------------------
-
- // Command wires
- wire cmd_send_imm_cf, cmd_chain_cf, cmd_reload_cf, cmd_stop_cf;
- wire [LINES_WIDTH-1:0] cmd_num_lines_cf;
-
- // Settings registers signals
- wire [ ADDR_WIDTH-1:0] rec_base_addr_sr; // Byte address
- wire [ ADDR_WIDTH-1:0] rec_buffer_size_sr; // Size in bytes
- wire [ ADDR_WIDTH-1:0] play_base_addr_sr; // Byte address
- wire [ ADDR_WIDTH-1:0] play_buffer_size_sr; // Size in bytes
- reg rec_restart;
- reg rec_restart_clear;
- wire [ CMD_WIDTH-1:0] command;
- wire command_valid;
- reg play_halt;
- reg play_halt_clear;
- wire [COUNT_WIDTH:0] play_max_len_sr;
-
- // Command FIFO
- wire cmd_fifo_valid;
- reg cmd_fifo_ready;
-
- // Record Data FIFO (Input)
- wire [DATA_WIDTH-1:0] rec_fifo_o_tdata;
- wire rec_fifo_o_tvalid;
- wire rec_fifo_o_tready;
- wire [ 15:0] rec_fifo_occupied;
-
- // Playback Data FIFO (Output)
- wire [DATA_WIDTH-1:0] play_fifo_i_tdata;
- wire play_fifo_i_tvalid;
- wire play_fifo_i_tready;
- wire [ 15:0] play_fifo_space; // Free space in play_axi_fifo
-
- // Buffer usage registers
- reg [ADDR_WIDTH-1:0] rec_buffer_avail; // Amount of free buffer space in words
- reg [ADDR_WIDTH-1:0] rec_buffer_used; // Amount of occupied buffer space in words
-
-
- //---------------------------------------------------------------------------
- // Registers
- //---------------------------------------------------------------------------
-
- // Record Base Address Register. Address is a byte address. This must be a
- // multiple of 8 bytes.
- setting_reg #(
- .my_addr (SR_REC_BASE_ADDR),
- .width (ADDR_WIDTH)
- ) sr_rec_base_addr (
- .clk (clk),
- .rst (rst),
- .strobe (set_stb),
- .addr (set_addr),
- .in (set_data),
- .out (rec_base_addr_sr),
- .changed ()
- );
-
-
- // Record Buffer Size Register. This indicates the portion of the RAM
- // allocated to the record buffer, in bytes. This should be a multiple of 8
- // bytes.
- setting_reg #(
- .my_addr (SR_REC_BUFFER_SIZE),
- .width (ADDR_WIDTH)
- ) sr_rec_buffer_size (
- .clk (clk),
- .rst (rst),
- .strobe (set_stb),
- .addr (set_addr),
- .in (set_data),
- .out (rec_buffer_size_sr),
- .changed ()
- );
-
-
- // Playback Base Address Register. Address is a byte address. This must be a
- // multiple of the 8 bytes.
- setting_reg #(
- .my_addr (SR_PLAY_BASE_ADDR),
- .width (ADDR_WIDTH)
- ) sr_play_base_addr (
- .clk (clk),
- .rst (rst),
- .strobe (set_stb),
- .addr (set_addr),
- .in (set_data),
- .out (play_base_addr_sr),
- .changed ()
- );
-
-
- // Playback Buffer Size Register. This indicates the portion of the RAM
- // allocated to the record buffer, in bytes. This should be a multiple of 8
- // bytes.
- setting_reg #(
- .my_addr (SR_PLAY_BUFFER_SIZE),
- .width (ADDR_WIDTH)
- ) sr_play_buffer_size (
- .clk (clk),
- .rst (rst),
- .strobe (set_stb),
- .addr (set_addr),
- .in (set_data),
- .out (play_buffer_size_sr),
- .changed ()
- );
-
-
- // Record Buffer Restart Register. Software must write to this register after
- // updating the base address or buffer size. A write to this register means
- // we need to stop any recording in progress and reset the record buffers
- // according to the current buffer base address and size registers.
- always @(posedge clk)
- begin : sr_restart
- if(rst) begin
- rec_restart <= 1'b0;
- end else begin
- if(set_stb & (set_addr == SR_REC_RESTART)) begin
- rec_restart <= 1'b1;
- end else if (rec_restart_clear) begin
- rec_restart <= 1'b0;
- end
- end
- end
-
-
- // Halt Register. A write to this register stops any replay operation as soon
- // as the current DRAM transaction completes.
- always @(posedge clk)
- begin : sr_halt
- if(rst) begin
- play_halt <= 1'b0;
- end else begin
- if(set_stb & (set_addr == SR_RX_CTRL_HALT)) begin
- play_halt <= 1'b1;
- end else if (play_halt_clear) begin
- play_halt <= 1'b0;
- end
- end
- end
-
-
- // Play Command Register
- //
- // This register mirrors the behavior of the RFNoC RX radio block. All
- // commands are queued up in the replay command FIFO. The fields are as
- // follows.
- //
- // send_imm [31] Send command immediately (don't use time).
- //
- // chain [30] When done with num_lines, immediately run next command.
- //
- // reload [29] When done with num_lines, rerun the same command if
- // cmd_chain is set and no new command is available.
- //
- // stop [28] When done with num_lines, stop transferring if
- // cmd_chain is set.
- //
- // num_lines [27:0] Number of samples to transfer to/from block.
- //
- setting_reg #(
- .my_addr (SR_RX_CTRL_COMMAND),
- .width (CMD_WIDTH)
- ) sr_command (
- .clk (clk),
- .rst (rst),
- .strobe (set_stb),
- .addr (set_addr),
- .in (set_data),
- .out (command),
- .changed (command_valid)
- );
-
-
- // Max Length Register. This register sets the number of words for the
- // maximum packet size.
- setting_reg #(
- .my_addr (SR_RX_CTRL_MAXLEN),
- .width (COUNT_WIDTH+1),
- .at_reset({1'b1, {COUNT_WIDTH{1'b0}}})
- ) sr_max_len (
- .clk (clk),
- .rst (rst),
- .strobe (set_stb),
- .addr (set_addr),
- .in (set_data),
- .out (play_max_len_sr),
- .changed ()
- );
-
-
- // Implement register read
- always @(*) begin
- case (rb_addr)
- SR_REC_BASE_ADDR : rb_data = rec_base_addr_sr;
- SR_REC_BUFFER_SIZE : rb_data = rec_buffer_size_sr;
- SR_REC_FULLNESS : rb_data = rec_buffer_used * WORD_SIZE;
- SR_PLAY_BASE_ADDR : rb_data = play_base_addr_sr;
- SR_PLAY_BUFFER_SIZE : rb_data = play_buffer_size_sr;
- SR_RX_CTRL_MAXLEN : rb_data = play_max_len_sr;
- default : rb_data = 32'h0;
- endcase
- end
-
-
- //---------------------------------------------------------------------------
- // Playback Command FIFO
- //---------------------------------------------------------------------------
- //
- // This block queues up commands for playback control.
- //
- //---------------------------------------------------------------------------
-
- axi_fifo_short #(
- .WIDTH (CMD_WIDTH)
- ) command_fifo (
- .clk (clk),
- .reset (rst),
- .clear (play_halt_clear),
- .i_tdata (command),
- .i_tvalid (command_valid),
- .i_tready (),
- .o_tdata ({cmd_send_imm_cf, cmd_chain_cf, cmd_reload_cf, cmd_stop_cf, cmd_num_lines_cf}),
- .o_tvalid (cmd_fifo_valid),
- .o_tready (cmd_fifo_ready),
- .occupied (),
- .space ()
- );
-
-
- //---------------------------------------------------------------------------
- // Record Input Data FIFO
- //---------------------------------------------------------------------------
- //
- // This FIFO stores data to be recording into the RAM buffer.
- //
- //---------------------------------------------------------------------------
-
- axi_fifo #(
- .WIDTH (DATA_WIDTH),
- .SIZE (REC_FIFO_ADDR_WIDTH)
- ) rec_axi_fifo (
- .clk (clk),
- .reset (rst),
- .clear (1'b0),
- //
- .i_tdata (i_tdata),
- .i_tvalid (i_tvalid),
- .i_tready (i_tready),
- //
- .o_tdata (rec_fifo_o_tdata),
- .o_tvalid (rec_fifo_o_tvalid),
- .o_tready (rec_fifo_o_tready),
- //
- .space (),
- .occupied (rec_fifo_occupied)
- );
-
-
- //---------------------------------------------------------------------------
- // Record State Machine
- //---------------------------------------------------------------------------
-
- // FSM States
- localparam REC_WAIT_FIFO = 0;
- localparam REC_CHECK_ALIGN = 1;
- localparam REC_DMA_REQ = 2;
- localparam REC_WAIT_DMA_START = 3;
- localparam REC_WAIT_DMA_COMMIT = 4;
-
- // State Signals
- reg [2:0] rec_state;
-
- // Registers
- reg [ADDR_WIDTH-1:0] rec_base_addr; // Last base address pulled from settings register
- reg [ADDR_WIDTH-1:0] rec_buffer_size; // Last buffer size pulled from settings register
- reg [ADDR_WIDTH-1:0] rec_addr; // Current offset into record buffer
- reg [ADDR_WIDTH-1:0] rec_size; // Number of words to transfer next
- reg [ADDR_WIDTH-1:0] rec_size_0; // Pipeline stage for computation of rec_size
-
- reg signed [ADDR_WIDTH:0] rec_size_aligned; // rec_size reduced to not cross 4k boundary
-
- // Timer to count how many cycles we've been waiting for new data
- reg [$clog2(DATA_WAIT_TIMEOUT+1)-1:0] rec_wait_timer;
- reg rec_wait_timeout;
-
- always @(posedge clk) begin
- if (rst) begin
- rec_state <= REC_WAIT_FIFO;
- rec_addr <= 0;
- write_ctrl_valid <= 1'b0;
-
- rec_buffer_avail <= 0;
- rec_buffer_used <= 0;
- rec_wait_timer <= 0;
- rec_wait_timeout <= 0;
-
- end else begin
-
- // Default assignments
- rec_restart_clear <= 1'b0;
-
- // Update wait timer
- if (i_tvalid || !rec_fifo_occupied) begin
- // If a new word is presented to the input FIFO, or the FIFO is empty,
- // then reset the timer.
- rec_wait_timer <= 0;
- rec_wait_timeout <= 1'b0;
- end else if (rec_fifo_occupied) begin
- // If no new word is written, but there's data in the FIFO, update the
- // timer. Latch timeout condition when we reach out limit.
- rec_wait_timer <= rec_wait_timer + 1;
-
- if (rec_wait_timer == DATA_WAIT_TIMEOUT) begin
- rec_wait_timeout <= 1'b1;
- end
- end
-
- // Pre-calculate the aligned size
- rec_size_aligned <= $signed(AXI_ALIGNMENT) - $signed(rec_addr & (AXI_ALIGNMENT-1));
-
- //
- // State logic
- //
- case (rec_state)
-
- REC_WAIT_FIFO : begin
- // Wait until there's enough data to initiate a transfer from the
- // FIFO to the RAM.
-
- // Check if a restart was requested on the record interface
- if (rec_restart) begin
- rec_restart_clear <= 1'b1;
-
- // Latch the new register values. We don't want them to change
- // while we're running.
- rec_base_addr <= rec_base_addr_sr;
- rec_buffer_size <= rec_buffer_size_sr / WORD_SIZE; // Store size in words
-
- // Reset counters and address any time we update the buffer size or
- // base address.
- rec_buffer_avail <= rec_buffer_size_sr / WORD_SIZE; // Store size in words
- rec_buffer_used <= 0;
- rec_addr <= rec_base_addr_sr;
-
- // Check if there's room left in the record RAM buffer
- end else if (rec_buffer_used < rec_buffer_size) begin
- // See if we can transfer a full burst
- if (rec_fifo_occupied >= MEM_BURST_SIZE && rec_buffer_avail >= MEM_BURST_SIZE) begin
- rec_size_0 <= MEM_BURST_SIZE;
- rec_state <= REC_CHECK_ALIGN;
-
- // Otherwise, if we've been waiting a long time, see if we can
- // transfer less than a burst.
- end else if (rec_fifo_occupied > 0 && rec_wait_timeout) begin
- rec_size_0 <= (rec_fifo_occupied <= rec_buffer_avail) ?
- rec_fifo_occupied : rec_buffer_avail;
- rec_state <= REC_CHECK_ALIGN;
- end
- end
- end
-
- REC_CHECK_ALIGN : begin
- // Check the address alignment, since AXI requires that an access not
- // cross 4k boundaries (boo), and the axi_dma_master doesn't handle
- // this automatically (boo again).
- rec_size <= ($signed({1'b0,rec_size_0}) > rec_size_aligned) ?
- rec_size_aligned : rec_size_0;
-
- // DMA interface is ready, so transaction will begin
- rec_state <= REC_DMA_REQ;
- end
-
- REC_DMA_REQ : begin
- // The write count written to the DMA engine should be 1 less than
- // the number of words you want to write (not the number of bytes).
- write_count <= rec_size - 1;
-
- // Create the physical RAM byte address by combining the address and
- // base address.
- write_addr <= rec_addr;
-
- // Once the interface is ready, make the DMA request
- if (write_ctrl_ready) begin
- // Request the write transaction
- write_ctrl_valid <= 1'b1;
- rec_state <= REC_WAIT_DMA_START;
- end
- end
-
- REC_WAIT_DMA_START : begin
- // Wait until DMA interface deasserts ready, indicating it has
- // started on the request.
- write_ctrl_valid <= 1'b0;
- if (!write_ctrl_ready) begin
- rec_state <= REC_WAIT_DMA_COMMIT;
- end
- end
-
- REC_WAIT_DMA_COMMIT : begin
- // Wait for the DMA interface to reassert write_ctrl_ready, which
- // signals that the DMA engine has received a response for the whole
- // write transaction and (we assume) it has been committed to RAM.
- // After this, we can update the write address and start the next
- // transaction.
- if (write_ctrl_ready) begin
- rec_addr <= rec_addr + (rec_size * WORD_SIZE);
- rec_buffer_used <= rec_buffer_used + rec_size;
- rec_buffer_avail <= rec_buffer_avail - rec_size;
- rec_state <= REC_WAIT_FIFO;
- end
- end
-
- default : begin
- rec_state <= REC_WAIT_FIFO;
- end
-
- endcase
- end
- end
-
- // Connect output of record FIFO to input of DMA write interface
- assign write_data = rec_fifo_o_tdata;
- assign write_data_valid = rec_fifo_o_tvalid;
- assign rec_fifo_o_tready = write_data_ready;
-
-
- //---------------------------------------------------------------------------
- // Playback State Machine
- //---------------------------------------------------------------------------
-
- // FSM States
- localparam PLAY_IDLE = 0;
- localparam PLAY_WAIT_DATA_READY = 1;
- localparam PLAY_SIZE_CALC = 2;
- localparam PLAY_DMA_REQ = 3;
- localparam PLAY_WAIT_DMA_START = 4;
- localparam PLAY_WAIT_DMA_COMMIT = 5;
- localparam PLAY_DONE_CHECK = 6;
-
- // State Signals
- reg [2:0] play_state;
-
- // Registers
- reg [ADDR_WIDTH-1:0] play_base_addr; // Last base address pulled from settings register
- reg [ADDR_WIDTH-1:0] play_buffer_size; // Last buffer size pulled from settings register
- reg [ADDR_WIDTH-1:0] play_addr; // Current byte offset into record buffer
- reg [ADDR_WIDTH-1:0] play_addr_0; // Pipeline stage for computing play_addr
- reg [ADDR_WIDTH-1:0] play_addr_1; // Pipeline stage for computing play_addr
- reg [ADDR_WIDTH-1:0] play_buffer_end; // Address of location after end of buffer
- reg [ADDR_WIDTH-1:0] max_dma_size; // Maximum size of next transfer, in words
- //
- reg [LINES_WIDTH-1:0] cmd_num_lines; // Copy of cmd_num_lines from last command
- reg [LINES_WIDTH-1:0] play_words_remaining; // Number of lines left to read for command
- reg cmd_chain; // Copy of cmd_chain from last command
- reg cmd_reload; // Copy of cmd_reload from last command
-
- reg play_full_burst_avail; // True if we there's a full burst to read
- reg play_buffer_avail_nonzero; // True if > 0
- reg cmd_num_lines_cf_nonzero; // True if > 0
- reg max_dma_size_ok; // True if it's OK to read max_dma_size
-
- reg [ADDR_WIDTH-1:0] max_dma_size_m1; // max_dma_size - 1
- reg [ADDR_WIDTH-1:0] play_words_remaining_m1; // play_words_remaining - 1
-
- reg [ADDR_WIDTH-1:0] play_buffer_avail; // Number of words left to read in record buffer
- reg [ADDR_WIDTH-1:0] play_buffer_avail_0; // Pipeline stage for computing play_buffer_avail
-
- always @(posedge clk)
- begin
- if (rst) begin
- play_state <= PLAY_IDLE;
- cmd_fifo_ready <= 1'b0;
-
- end else begin
-
- // Calculate how many words are left to read from the record buffer
- play_full_burst_avail <= (play_buffer_avail >= MEM_BURST_SIZE);
- play_buffer_avail_nonzero <= (play_buffer_avail > 0);
- cmd_num_lines_cf_nonzero <= (cmd_num_lines_cf > 0);
- play_buffer_end <= play_base_addr_sr + play_buffer_size_sr;
-
- // Default values
- cmd_fifo_ready <= 1'b0;
- read_ctrl_valid <= 1'b0;
- play_halt_clear <= 1'b0;
-
- //
- // State logic
- //
- case (play_state)
- PLAY_IDLE : begin
- // Always start reading at the start of the record buffer
- play_addr <= play_base_addr_sr;
-
- // Save off command info, in case we need to repeat the command
- cmd_num_lines <= cmd_num_lines_cf;
- cmd_reload <= cmd_reload_cf;
- cmd_chain <= cmd_chain_cf;
-
- // Save the buffer info so it doesn't update during playback
- play_base_addr <= play_base_addr_sr;
- play_buffer_size <= play_buffer_size_sr;
- play_buffer_avail <= play_buffer_size_sr / WORD_SIZE;
-
- // Wait until we receive a command and we have enough data recorded
- // to honor it.
- if (cmd_fifo_valid && ~play_halt_clear) begin
- // Load the number of word remaining to complete this command
- play_words_remaining <= cmd_num_lines_cf;
-
- // We don't support time yet, so we require send_imm to do
- // anything. Also, we can't do anything until we have data recorded.
- if (cmd_stop_cf) begin
- // Do nothing, except clear command from the FIFO
- cmd_fifo_ready <= 1'b1;
- end else if (cmd_send_imm_cf
- && play_buffer_avail_nonzero
- && cmd_num_lines_cf_nonzero) begin
- // Dequeue the command from the FIFO
- cmd_fifo_ready <= 1'b1;
-
- play_state <= PLAY_WAIT_DATA_READY;
- end
- end else if (play_halt) begin
- // In case we get a HALT after a command has finished
- play_halt_clear <= 1'b1;
- end
- end
-
- PLAY_WAIT_DATA_READY : begin
- // Save the maximum size we can read from RAM
- max_dma_size <= play_full_burst_avail ? MEM_BURST_SIZE : play_buffer_avail;
-
- // Check if we got a halt command while waiting
- if (play_halt) begin
- play_halt_clear <= 1'b1;
- play_state <= PLAY_IDLE;
-
- // Wait for output FIFO to empty sufficiently so we can read an
- // entire burst at once. This may be more space than needed, but we
- // won't know the exact size until the next state.
- end else if (play_fifo_space >= MEM_BURST_SIZE) begin
- play_state <= PLAY_SIZE_CALC;
- end
- end
-
- PLAY_SIZE_CALC : begin
- // Do some intermediate calculations to determine what the read_count
- // should be.
- play_words_remaining_m1 <= play_words_remaining-1;
- max_dma_size_m1 <= max_dma_size-1;
- max_dma_size_ok <= play_words_remaining >= max_dma_size;
- play_state <= PLAY_DMA_REQ;
- end
-
- PLAY_DMA_REQ : begin
- // Load the size of the next read into a register. We try to read the
- // max amount available (up to the burst size) or however many words
- // are needed to reach the end of the RAM buffer.
- //
- // The read count written to the DMA engine should be 1 less than the
- // number of words you want to read (not the number of bytes).
- read_count <= max_dma_size_ok ? max_dma_size_m1 : play_words_remaining_m1;
-
- // Load the address to read. Note that we don't do an alignment check
- // since we assume that multiples of MEM_BURST_SIZE meet the
- // AXI_ALIGNMENT requirement.
- read_addr <= play_addr;
-
- // Request the read transaction as soon as DMA interface is ready
- if (read_ctrl_ready) begin
- read_ctrl_valid <= 1'b1;
- play_state <= PLAY_WAIT_DMA_START;
- end
- end
-
- PLAY_WAIT_DMA_START : begin
- // Wait until DMA interface deasserts ready, indicating it has
- // started on the request.
- read_ctrl_valid <= 1'b0;
- if (!read_ctrl_ready) begin
- // Update values for next transaction
- play_addr_0 <= play_addr + ({{(ADDR_WIDTH-COUNT_WIDTH){1'b0}}, read_count} + 1) * WORD_SIZE;
- play_words_remaining <= play_words_remaining - ({1'b0, read_count} + 1);
- play_buffer_avail_0 <= play_buffer_avail - ({1'b0, read_count} + 1);
-
- play_state <= PLAY_WAIT_DMA_COMMIT;
- end
- end
-
- PLAY_WAIT_DMA_COMMIT : begin
- // Wait for the DMA interface to reassert read_ctrl_ready, which
- // signals that the DMA engine has received a response for the whole
- // read transaction.
- if (read_ctrl_ready) begin
- // Check if we need to wrap the address for the next transaction
- if (play_addr_0 >= play_buffer_end) begin
- play_addr_1 <= play_base_addr_sr;
- play_buffer_avail <= play_buffer_size_sr / WORD_SIZE;
- end else begin
- play_addr_1 <= play_addr_0;
- play_buffer_avail <= play_buffer_avail_0;
- end
-
- play_state <= PLAY_DONE_CHECK;
- end
- end
-
- PLAY_DONE_CHECK : begin
- play_addr <= play_addr_1;
-
- // Check if we have more data to transfer for this command
- if (play_words_remaining) begin
- play_state <= PLAY_WAIT_DATA_READY;
-
- // Check if we're chaining
- end else if (cmd_chain) begin
- // Check if there's a new command waiting
- if (cmd_fifo_valid) begin
- // Load the next command. Note that we don't reset the playback
- // address when commands are chained together.
- play_words_remaining <= cmd_num_lines_cf;
- cmd_num_lines <= cmd_num_lines_cf;
- cmd_reload <= cmd_reload_cf;
- cmd_chain <= cmd_chain_cf;
-
- // Dequeue the command from the FIFO
- cmd_fifo_ready <= 1'b1;
-
- // Stop if it's a stop command, otherwise restart
- if (cmd_stop_cf) begin
- play_state <= PLAY_IDLE;
- end else begin
- play_state <= PLAY_WAIT_DATA_READY;
- end
-
- // Check if we need to restart the previous command
- end else if (cmd_reload) begin
- play_words_remaining <= cmd_num_lines;
- play_state <= PLAY_WAIT_DATA_READY;
- end
- // Nothing left to do
- end else begin
- play_state <= PLAY_IDLE;
- end
- end
- endcase
-
- end
- end
-
- // Connect output of DMA master to playback data FIFO
- assign play_fifo_i_tdata = read_data;
- assign play_fifo_i_tvalid = read_data_valid;
- assign read_data_ready = play_fifo_i_tready;
-
-
- //---------------------------------------------------------------------------
- // TLAST Generation
- //---------------------------------------------------------------------------
- //
- // This block monitors the signals to/from the DMA master and generates the
- // TLAST signal. We assert TLAST at the end of every read transaction and
- // after every play_max_len_sr words, so that no packets are longer than the
- // length indicated by the max_len register.
- //
- // The timing of this block relies on the fact that read_ctrl_ready is not
- // reasserted by the DMA master until after TLAST gets asserted.
- //
- //---------------------------------------------------------------------------
-
- reg [COUNT_WIDTH-1:0] read_counter;
- reg [COUNT_WIDTH-1:0] length_counter;
- reg play_fifo_i_tlast;
-
- always @(posedge clk)
- begin
- if (rst) begin
- play_fifo_i_tlast <= 1'b0;
- end else begin
- // Check if we're requesting a read transaction
- if (read_ctrl_valid && read_ctrl_ready) begin
- // Initialize read_counter for new transaction
- read_counter <= read_count;
- length_counter <= play_max_len_sr;
-
- // If read_count is 0, then the first word is also the last word
- if (read_count == 0) begin
- play_fifo_i_tlast <= 1'b1;
- end
-
- // Track the number of words read out by DMA master
- end else if (read_data_valid && read_data_ready) begin
- read_counter <= read_counter - 1;
- length_counter <= length_counter - 1;
-
- // Check if the word currently being output is the last word of a
- // packet, which means we need to clear tlast.
- if (play_fifo_i_tlast) begin
- // But make sure that the next word isn't also the last of a DMA
- // burst, for which we will need to keep tlast asserted.
- if (read_counter != 1) begin
- play_fifo_i_tlast <= 1'b0;
- end
-
- // Restart length counter
- length_counter <= play_max_len_sr;
-
- // Check if the next word to be output should be the last of a packet.
- end else if (read_counter == 1 || length_counter == 2) begin
- play_fifo_i_tlast <= 1'b1;
- end
- end
-
- end
- end
-
-
- //---------------------------------------------------------------------------
- // Playback Output Data FIFO
- //---------------------------------------------------------------------------
- //
- // This FIFO buffers data that has been read out of RAM as part of a playback
- // operation.
- //
- //---------------------------------------------------------------------------
-
- axi_fifo #(
- .WIDTH (DATA_WIDTH+1),
- .SIZE (PLAY_FIFO_ADDR_WIDTH)
- ) play_axi_fifo (
- .clk (clk),
- .reset (rst),
- .clear (1'b0),
- //
- .i_tdata ({play_fifo_i_tlast, play_fifo_i_tdata}),
- .i_tvalid (play_fifo_i_tvalid),
- .i_tready (play_fifo_i_tready),
- //
- .o_tdata ({o_tlast, o_tdata}),
- .o_tvalid (o_tvalid),
- .o_tready (o_tready),
- //
- .space (play_fifo_space),
- .occupied ()
- );
-
-endmodule \ No newline at end of file