diff options
author | Wade Fife <wade.fife@ettus.com> | 2020-04-06 16:19:50 -0500 |
---|---|---|
committer | Aaron Rossetto <aaron.rossetto@ni.com> | 2020-08-04 15:40:08 -0500 |
commit | 6d92a1828121ca4b57d496bbf522820f961244b9 (patch) | |
tree | f0659ab6d1a6e1f8801db356e2237388d90724f2 /fpga/usrp3/lib/axi | |
parent | 24f8bb39fd2769ff93d11b21152a834500152de4 (diff) | |
download | uhd-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.srcs | 1 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi/axi_replay.v | 867 |
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 |