fpga: rfnoc: Add RFNoC Replay block
Original-commit: 6d92a1828121ca4b57d496bbf522820f961244b9
This commit is contained in:
committed by
Aaron Rossetto
parent
b4fed123c8
commit
104a73e623
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,45 @@
|
||||
#
|
||||
# Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#
|
||||
|
||||
#-------------------------------------------------
|
||||
# Top-of-Makefile
|
||||
#-------------------------------------------------
|
||||
# Define BASE_DIR to point to the "top" dir
|
||||
BASE_DIR = $(abspath ../../../../top)
|
||||
# Include viv_sim_preamble after defining BASE_DIR
|
||||
include $(BASE_DIR)/../tools/make/viv_sim_preamble.mak
|
||||
|
||||
#-------------------------------------------------
|
||||
# Design Specific
|
||||
#-------------------------------------------------
|
||||
# Include makefiles and sources for the DUT and its
|
||||
# dependencies.
|
||||
include $(BASE_DIR)/../lib/rfnoc/core/Makefile.srcs
|
||||
include $(BASE_DIR)/../lib/rfnoc/utils/Makefile.srcs
|
||||
include Makefile.srcs
|
||||
|
||||
DESIGN_SRCS += $(abspath \
|
||||
$(RFNOC_CORE_SRCS) \
|
||||
$(RFNOC_UTIL_SRCS) \
|
||||
$(RFNOC_OOT_SRCS) \
|
||||
)
|
||||
|
||||
#-------------------------------------------------
|
||||
# Testbench Specific
|
||||
#-------------------------------------------------
|
||||
SIM_TOP = rfnoc_block_replay_all_tb
|
||||
SIM_SRCS = \
|
||||
$(abspath ../rfnoc_block_axi_ram_fifo/sim_axi_ram.sv) \
|
||||
$(abspath rfnoc_block_replay_tb.sv) \
|
||||
$(abspath rfnoc_block_replay_all_tb.sv) \
|
||||
|
||||
#-------------------------------------------------
|
||||
# Bottom-of-Makefile
|
||||
#-------------------------------------------------
|
||||
# Include all simulator specific makefiles here
|
||||
# Each should define a unique target to simulate
|
||||
# e.g. xsim, vsim, etc and a common "clean" target
|
||||
include $(BASE_DIR)/../tools/make/viv_simulator.mak
|
||||
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
#
|
||||
|
||||
##################################################
|
||||
# RFNoC Block Sources
|
||||
##################################################
|
||||
# Here, list all the files that are necessary to synthesize this block. Don't
|
||||
# include testbenches!
|
||||
# Make sure that the source files are nicely detectable by a regex. Best to put
|
||||
# one on each line.
|
||||
# The first argument to addprefix is the current path to this Makefile, so the
|
||||
# path list is always absolute, regardless of from where we're including or
|
||||
# calling this file. RFNOC_OOT_SRCS needs to be a simply expanded variable
|
||||
# (not a recursively expanded variable), and we take care of that in the build
|
||||
# infrastructure.
|
||||
RFNOC_OOT_SRCS += $(addprefix $(dir $(abspath $(lastword $(MAKEFILE_LIST)))), \
|
||||
rfnoc_block_replay_regs.vh \
|
||||
axis_replay.v \
|
||||
noc_shell_replay.v \
|
||||
rfnoc_block_replay.v \
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,306 @@
|
||||
//
|
||||
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: noc_shell_replay
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This is a tool-generated NoC-shell for the replay block.
|
||||
// See the RFNoC specification for more information about NoC shells.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// THIS_PORTID : Control crossbar port to which this block is connected
|
||||
// CHDR_W : AXIS-CHDR data bus width
|
||||
// MTU : Maximum transmission unit (i.e., maximum packet size in
|
||||
//
|
||||
|
||||
`default_nettype none
|
||||
|
||||
|
||||
module noc_shell_replay #(
|
||||
parameter [9:0] THIS_PORTID = 10'd0,
|
||||
parameter CHDR_W = 64,
|
||||
parameter [5:0] MTU = 10,
|
||||
parameter NUM_PORTS = 2,
|
||||
parameter MEM_DATA_W = 64,
|
||||
parameter MEM_ADDR_W = 30
|
||||
) (
|
||||
//---------------------
|
||||
// Framework Interface
|
||||
//---------------------
|
||||
|
||||
// RFNoC Framework Clocks
|
||||
input wire rfnoc_chdr_clk,
|
||||
input wire rfnoc_ctrl_clk,
|
||||
input wire mem_clk,
|
||||
|
||||
// NoC Shell Generated Resets
|
||||
output wire rfnoc_chdr_rst,
|
||||
output wire rfnoc_ctrl_rst,
|
||||
output wire mem_rst,
|
||||
|
||||
// RFNoC Backend Interface
|
||||
input wire [511:0] rfnoc_core_config,
|
||||
output wire [511:0] rfnoc_core_status,
|
||||
|
||||
// AXIS-CHDR Input Ports (from framework)
|
||||
input wire [(0+NUM_PORTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata,
|
||||
input wire [(0+NUM_PORTS)-1:0] s_rfnoc_chdr_tlast,
|
||||
input wire [(0+NUM_PORTS)-1:0] s_rfnoc_chdr_tvalid,
|
||||
output wire [(0+NUM_PORTS)-1:0] s_rfnoc_chdr_tready,
|
||||
// AXIS-CHDR Output Ports (to framework)
|
||||
output wire [(0+NUM_PORTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata,
|
||||
output wire [(0+NUM_PORTS)-1:0] m_rfnoc_chdr_tlast,
|
||||
output wire [(0+NUM_PORTS)-1:0] m_rfnoc_chdr_tvalid,
|
||||
input wire [(0+NUM_PORTS)-1:0] m_rfnoc_chdr_tready,
|
||||
|
||||
// AXIS-Ctrl Control Input Port (from framework)
|
||||
input wire [31:0] s_rfnoc_ctrl_tdata,
|
||||
input wire s_rfnoc_ctrl_tlast,
|
||||
input wire s_rfnoc_ctrl_tvalid,
|
||||
output wire s_rfnoc_ctrl_tready,
|
||||
// AXIS-Ctrl Control Output Port (to framework)
|
||||
output wire [31:0] m_rfnoc_ctrl_tdata,
|
||||
output wire m_rfnoc_ctrl_tlast,
|
||||
output wire m_rfnoc_ctrl_tvalid,
|
||||
input wire m_rfnoc_ctrl_tready,
|
||||
|
||||
//---------------------
|
||||
// Client Interface
|
||||
//---------------------
|
||||
|
||||
// CtrlPort Clock and Reset
|
||||
output wire ctrlport_clk,
|
||||
output wire ctrlport_rst,
|
||||
// CtrlPort Master
|
||||
output wire m_ctrlport_req_wr,
|
||||
output wire m_ctrlport_req_rd,
|
||||
output wire [19:0] m_ctrlport_req_addr,
|
||||
output wire [31:0] m_ctrlport_req_data,
|
||||
input wire m_ctrlport_resp_ack,
|
||||
input wire [31:0] m_ctrlport_resp_data,
|
||||
|
||||
// AXI-Stream Data Clock and Reset
|
||||
output wire axis_data_clk,
|
||||
output wire axis_data_rst,
|
||||
// Data Stream to User Logic: in
|
||||
output wire [NUM_PORTS*32*MEM_DATA_W/32-1:0] m_in_axis_tdata,
|
||||
output wire [NUM_PORTS*MEM_DATA_W/32-1:0] m_in_axis_tkeep,
|
||||
output wire [NUM_PORTS-1:0] m_in_axis_tlast,
|
||||
output wire [NUM_PORTS-1:0] m_in_axis_tvalid,
|
||||
input wire [NUM_PORTS-1:0] m_in_axis_tready,
|
||||
output wire [NUM_PORTS*64-1:0] m_in_axis_ttimestamp,
|
||||
output wire [NUM_PORTS-1:0] m_in_axis_thas_time,
|
||||
output wire [NUM_PORTS*16-1:0] m_in_axis_tlength,
|
||||
output wire [NUM_PORTS-1:0] m_in_axis_teov,
|
||||
output wire [NUM_PORTS-1:0] m_in_axis_teob,
|
||||
// Data Stream to User Logic: out
|
||||
input wire [NUM_PORTS*32*MEM_DATA_W/32-1:0] s_out_axis_tdata,
|
||||
input wire [NUM_PORTS*MEM_DATA_W/32-1:0] s_out_axis_tkeep,
|
||||
input wire [NUM_PORTS-1:0] s_out_axis_tlast,
|
||||
input wire [NUM_PORTS-1:0] s_out_axis_tvalid,
|
||||
output wire [NUM_PORTS-1:0] s_out_axis_tready,
|
||||
input wire [NUM_PORTS*64-1:0] s_out_axis_ttimestamp,
|
||||
input wire [NUM_PORTS-1:0] s_out_axis_thas_time,
|
||||
input wire [NUM_PORTS*16-1:0] s_out_axis_tlength,
|
||||
input wire [NUM_PORTS-1:0] s_out_axis_teov,
|
||||
input wire [NUM_PORTS-1:0] s_out_axis_teob
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Backend Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
wire data_i_flush_en;
|
||||
wire [31:0] data_i_flush_timeout;
|
||||
wire [63:0] data_i_flush_active;
|
||||
wire [63:0] data_i_flush_done;
|
||||
wire data_o_flush_en;
|
||||
wire [31:0] data_o_flush_timeout;
|
||||
wire [63:0] data_o_flush_active;
|
||||
wire [63:0] data_o_flush_done;
|
||||
|
||||
backend_iface #(
|
||||
.NOC_ID (32'h4E91A000),
|
||||
.NUM_DATA_I (0+NUM_PORTS),
|
||||
.NUM_DATA_O (0+NUM_PORTS),
|
||||
.CTRL_FIFOSIZE ($clog2(32)),
|
||||
.MTU (MTU)
|
||||
) backend_iface_i (
|
||||
.rfnoc_chdr_clk (rfnoc_chdr_clk),
|
||||
.rfnoc_chdr_rst (rfnoc_chdr_rst),
|
||||
.rfnoc_ctrl_clk (rfnoc_ctrl_clk),
|
||||
.rfnoc_ctrl_rst (rfnoc_ctrl_rst),
|
||||
.rfnoc_core_config (rfnoc_core_config),
|
||||
.rfnoc_core_status (rfnoc_core_status),
|
||||
.data_i_flush_en (data_i_flush_en),
|
||||
.data_i_flush_timeout (data_i_flush_timeout),
|
||||
.data_i_flush_active (data_i_flush_active),
|
||||
.data_i_flush_done (data_i_flush_done),
|
||||
.data_o_flush_en (data_o_flush_en),
|
||||
.data_o_flush_timeout (data_o_flush_timeout),
|
||||
.data_o_flush_active (data_o_flush_active),
|
||||
.data_o_flush_done (data_o_flush_done)
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Reset Generation
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
wire mem_rst_pulse;
|
||||
|
||||
pulse_synchronizer #(.MODE ("POSEDGE")) pulse_synchronizer_mem (
|
||||
.clk_a(rfnoc_chdr_clk), .rst_a(1'b0), .pulse_a (rfnoc_chdr_rst), .busy_a (),
|
||||
.clk_b(mem_clk), .pulse_b (mem_rst_pulse)
|
||||
);
|
||||
|
||||
pulse_stretch_min #(.LENGTH(32)) pulse_stretch_min_mem (
|
||||
.clk(mem_clk), .rst(1'b0),
|
||||
.pulse_in(mem_rst_pulse), .pulse_out(mem_rst)
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Control Path
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
assign ctrlport_clk = mem_clk;
|
||||
assign ctrlport_rst = mem_rst;
|
||||
|
||||
ctrlport_endpoint #(
|
||||
.THIS_PORTID (THIS_PORTID),
|
||||
.SYNC_CLKS (0),
|
||||
.AXIS_CTRL_MST_EN (0),
|
||||
.AXIS_CTRL_SLV_EN (1),
|
||||
.SLAVE_FIFO_SIZE ($clog2(32))
|
||||
) ctrlport_endpoint_i (
|
||||
.rfnoc_ctrl_clk (rfnoc_ctrl_clk),
|
||||
.rfnoc_ctrl_rst (rfnoc_ctrl_rst),
|
||||
.ctrlport_clk (ctrlport_clk),
|
||||
.ctrlport_rst (ctrlport_rst),
|
||||
.s_rfnoc_ctrl_tdata (s_rfnoc_ctrl_tdata),
|
||||
.s_rfnoc_ctrl_tlast (s_rfnoc_ctrl_tlast),
|
||||
.s_rfnoc_ctrl_tvalid (s_rfnoc_ctrl_tvalid),
|
||||
.s_rfnoc_ctrl_tready (s_rfnoc_ctrl_tready),
|
||||
.m_rfnoc_ctrl_tdata (m_rfnoc_ctrl_tdata),
|
||||
.m_rfnoc_ctrl_tlast (m_rfnoc_ctrl_tlast),
|
||||
.m_rfnoc_ctrl_tvalid (m_rfnoc_ctrl_tvalid),
|
||||
.m_rfnoc_ctrl_tready (m_rfnoc_ctrl_tready),
|
||||
.m_ctrlport_req_wr (m_ctrlport_req_wr),
|
||||
.m_ctrlport_req_rd (m_ctrlport_req_rd),
|
||||
.m_ctrlport_req_addr (m_ctrlport_req_addr),
|
||||
.m_ctrlport_req_data (m_ctrlport_req_data),
|
||||
.m_ctrlport_req_byte_en (),
|
||||
.m_ctrlport_req_has_time (),
|
||||
.m_ctrlport_req_time (),
|
||||
.m_ctrlport_resp_ack (m_ctrlport_resp_ack),
|
||||
.m_ctrlport_resp_status (2'b0),
|
||||
.m_ctrlport_resp_data (m_ctrlport_resp_data),
|
||||
.s_ctrlport_req_wr (1'b0),
|
||||
.s_ctrlport_req_rd (1'b0),
|
||||
.s_ctrlport_req_addr (20'b0),
|
||||
.s_ctrlport_req_portid (10'b0),
|
||||
.s_ctrlport_req_rem_epid (16'b0),
|
||||
.s_ctrlport_req_rem_portid (10'b0),
|
||||
.s_ctrlport_req_data (32'b0),
|
||||
.s_ctrlport_req_byte_en (4'hF),
|
||||
.s_ctrlport_req_has_time (1'b0),
|
||||
.s_ctrlport_req_time (64'b0),
|
||||
.s_ctrlport_resp_ack (),
|
||||
.s_ctrlport_resp_status (),
|
||||
.s_ctrlport_resp_data ()
|
||||
);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Data Path
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
genvar i;
|
||||
|
||||
assign axis_data_clk = mem_clk;
|
||||
assign axis_data_rst = mem_rst;
|
||||
|
||||
//---------------------
|
||||
// Input Data Paths
|
||||
//---------------------
|
||||
|
||||
for (i = 0; i < NUM_PORTS; i = i + 1) begin: gen_input_in
|
||||
chdr_to_axis_data #(
|
||||
.CHDR_W (CHDR_W),
|
||||
.ITEM_W (32),
|
||||
.NIPC (MEM_DATA_W/32),
|
||||
.SYNC_CLKS (0),
|
||||
.INFO_FIFO_SIZE ($clog2(32)),
|
||||
.PYLD_FIFO_SIZE ($clog2(MTU))
|
||||
) chdr_to_axis_data_in_in (
|
||||
.axis_chdr_clk (rfnoc_chdr_clk),
|
||||
.axis_chdr_rst (rfnoc_chdr_rst),
|
||||
.axis_data_clk (axis_data_clk),
|
||||
.axis_data_rst (axis_data_rst),
|
||||
.s_axis_chdr_tdata (s_rfnoc_chdr_tdata[((0+i)*CHDR_W)+:CHDR_W]),
|
||||
.s_axis_chdr_tlast (s_rfnoc_chdr_tlast[0+i]),
|
||||
.s_axis_chdr_tvalid (s_rfnoc_chdr_tvalid[0+i]),
|
||||
.s_axis_chdr_tready (s_rfnoc_chdr_tready[0+i]),
|
||||
.m_axis_tdata (m_in_axis_tdata[(32*MEM_DATA_W/32)*i+:(32*MEM_DATA_W/32)]),
|
||||
.m_axis_tkeep (m_in_axis_tkeep[MEM_DATA_W/32*i+:MEM_DATA_W/32]),
|
||||
.m_axis_tlast (m_in_axis_tlast[i]),
|
||||
.m_axis_tvalid (m_in_axis_tvalid[i]),
|
||||
.m_axis_tready (m_in_axis_tready[i]),
|
||||
.m_axis_ttimestamp (m_in_axis_ttimestamp[64*i+:64]),
|
||||
.m_axis_thas_time (m_in_axis_thas_time[i]),
|
||||
.m_axis_tlength (m_in_axis_tlength[16*i+:16]),
|
||||
.m_axis_teov (m_in_axis_teov[i]),
|
||||
.m_axis_teob (m_in_axis_teob[i]),
|
||||
.flush_en (data_i_flush_en),
|
||||
.flush_timeout (data_i_flush_timeout),
|
||||
.flush_active (data_i_flush_active[0+i]),
|
||||
.flush_done (data_i_flush_done[0+i])
|
||||
);
|
||||
end
|
||||
|
||||
//---------------------
|
||||
// Output Data Paths
|
||||
//---------------------
|
||||
|
||||
for (i = 0; i < NUM_PORTS; i = i + 1) begin: gen_output_out
|
||||
axis_data_to_chdr #(
|
||||
.CHDR_W (CHDR_W),
|
||||
.ITEM_W (32),
|
||||
.NIPC (MEM_DATA_W/32),
|
||||
.SYNC_CLKS (0),
|
||||
.INFO_FIFO_SIZE ($clog2(32)),
|
||||
.PYLD_FIFO_SIZE ($clog2(MTU)),
|
||||
.MTU (MTU),
|
||||
.SIDEBAND_AT_END (1)
|
||||
) axis_data_to_chdr_out_out (
|
||||
.axis_chdr_clk (rfnoc_chdr_clk),
|
||||
.axis_chdr_rst (rfnoc_chdr_rst),
|
||||
.axis_data_clk (axis_data_clk),
|
||||
.axis_data_rst (axis_data_rst),
|
||||
.m_axis_chdr_tdata (m_rfnoc_chdr_tdata[(0+i)*CHDR_W+:CHDR_W]),
|
||||
.m_axis_chdr_tlast (m_rfnoc_chdr_tlast[0+i]),
|
||||
.m_axis_chdr_tvalid (m_rfnoc_chdr_tvalid[0+i]),
|
||||
.m_axis_chdr_tready (m_rfnoc_chdr_tready[0+i]),
|
||||
.s_axis_tdata (s_out_axis_tdata[(32*MEM_DATA_W/32)*i+:(32*MEM_DATA_W/32)]),
|
||||
.s_axis_tkeep (s_out_axis_tkeep[MEM_DATA_W/32*i+:MEM_DATA_W/32]),
|
||||
.s_axis_tlast (s_out_axis_tlast[i]),
|
||||
.s_axis_tvalid (s_out_axis_tvalid[i]),
|
||||
.s_axis_tready (s_out_axis_tready[i]),
|
||||
.s_axis_ttimestamp (s_out_axis_ttimestamp[64*i+:64]),
|
||||
.s_axis_thas_time (s_out_axis_thas_time[i]),
|
||||
.s_axis_tlength (s_out_axis_tlength[16*i+:16]),
|
||||
.s_axis_teov (s_out_axis_teov[i]),
|
||||
.s_axis_teob (s_out_axis_teob[i]),
|
||||
.flush_en (data_o_flush_en),
|
||||
.flush_timeout (data_o_flush_timeout),
|
||||
.flush_active (data_o_flush_active[0+i]),
|
||||
.flush_done (data_o_flush_done[0+i])
|
||||
);
|
||||
end
|
||||
|
||||
endmodule // noc_shell_replay
|
||||
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,518 @@
|
||||
//
|
||||
// Copyright 2019 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: rfnoc_block_replay
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// RFNoC data record and playback block. This block has the ability to
|
||||
// capture all of the data that is sent to it and store it into an attached
|
||||
// memory using an AXI memory-mapped interface. It can then play back any
|
||||
// part of the data on demand or continuously. Timed playback is also
|
||||
// supported. See axis_replay.v for details of replay operation.
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// THIS_PORTID : Control crossbar port to which this block is connected
|
||||
// CHDR_W : AXIS-CHDR data bus width
|
||||
// MTU : Maximum transmission unit (i.e., maximum packet size in
|
||||
// CHDR words is 2**MTU).
|
||||
// NUM_PORTS : Number of replay instances to instantiate. Each one will
|
||||
// have its own register set and memory interface.
|
||||
// MEM_DATA_W : Data width to use for the memory interface.
|
||||
// MEM_ADDR_W : Byte address width to use for the memory interface.
|
||||
//
|
||||
|
||||
`default_nettype none
|
||||
|
||||
|
||||
module rfnoc_block_replay #(
|
||||
parameter [9:0] THIS_PORTID = 10'd0,
|
||||
parameter CHDR_W = 64,
|
||||
parameter [5:0] MTU = 10,
|
||||
parameter NUM_PORTS = 1,
|
||||
parameter MEM_DATA_W = 64,
|
||||
parameter MEM_ADDR_W = 30
|
||||
) (
|
||||
//---------------------------------------------------------------------------
|
||||
// AXIS-CHDR Port
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// RFNoC Framework Clocks and Resets
|
||||
input wire rfnoc_chdr_clk,
|
||||
|
||||
// AXIS-CHDR Input Ports (from framework)
|
||||
input wire [(0+NUM_PORTS)*CHDR_W-1:0] s_rfnoc_chdr_tdata,
|
||||
input wire [ (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tlast,
|
||||
input wire [ (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tvalid,
|
||||
output wire [ (0+NUM_PORTS)-1:0] s_rfnoc_chdr_tready,
|
||||
|
||||
// AXIS-CHDR Output Ports (to framework)
|
||||
output wire [(0+NUM_PORTS)*CHDR_W-1:0] m_rfnoc_chdr_tdata,
|
||||
output wire [ (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tlast,
|
||||
output wire [ (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tvalid,
|
||||
input wire [ (0+NUM_PORTS)-1:0] m_rfnoc_chdr_tready,
|
||||
|
||||
// RFNoC Backend Interface
|
||||
input wire [511:0] rfnoc_core_config,
|
||||
output wire [511:0] rfnoc_core_status,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// AXIS-Ctrl Port
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
input wire rfnoc_ctrl_clk,
|
||||
|
||||
// AXIS-Ctrl Input Port (from framework)
|
||||
input wire [31:0] s_rfnoc_ctrl_tdata,
|
||||
input wire s_rfnoc_ctrl_tlast,
|
||||
input wire s_rfnoc_ctrl_tvalid,
|
||||
output wire s_rfnoc_ctrl_tready,
|
||||
// AXIS-Ctrl Output Port (to framework)
|
||||
output wire [31:0] m_rfnoc_ctrl_tdata,
|
||||
output wire m_rfnoc_ctrl_tlast,
|
||||
output wire m_rfnoc_ctrl_tvalid,
|
||||
input wire m_rfnoc_ctrl_tready,
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// AXI Memory Mapped Interface
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// AXI Interface Clock and Reset
|
||||
input wire mem_clk,
|
||||
input wire axi_rst,
|
||||
|
||||
// AXI Write address channel
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_awid,
|
||||
output wire [ (NUM_PORTS*MEM_ADDR_W)-1:0] m_axi_awaddr,
|
||||
output wire [ (NUM_PORTS*8)-1:0] m_axi_awlen,
|
||||
output wire [ (NUM_PORTS*3)-1:0] m_axi_awsize,
|
||||
output wire [ (NUM_PORTS*2)-1:0] m_axi_awburst,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_awlock,
|
||||
output wire [ (NUM_PORTS*4)-1:0] m_axi_awcache,
|
||||
output wire [ (NUM_PORTS*3)-1:0] m_axi_awprot,
|
||||
output wire [ (NUM_PORTS*4)-1:0] m_axi_awqos,
|
||||
output wire [ (NUM_PORTS*4)-1:0] m_axi_awregion,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_awuser,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_awvalid,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_awready,
|
||||
// AXI Write data channel
|
||||
output wire [ (NUM_PORTS*MEM_DATA_W)-1:0] m_axi_wdata,
|
||||
output wire [(NUM_PORTS*MEM_DATA_W/8)-1:0] m_axi_wstrb,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_wlast,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_wuser,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_wvalid,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_wready,
|
||||
// AXI Write response channel signals
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_bid,
|
||||
input wire [ (NUM_PORTS*2)-1:0] m_axi_bresp,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_buser,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_bvalid,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_bready,
|
||||
// AXI Read address channel
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_arid,
|
||||
output wire [ (NUM_PORTS*MEM_ADDR_W)-1:0] m_axi_araddr,
|
||||
output wire [ (NUM_PORTS*8)-1:0] m_axi_arlen,
|
||||
output wire [ (NUM_PORTS*3)-1:0] m_axi_arsize,
|
||||
output wire [ (NUM_PORTS*2)-1:0] m_axi_arburst,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_arlock,
|
||||
output wire [ (NUM_PORTS*4)-1:0] m_axi_arcache,
|
||||
output wire [ (NUM_PORTS*3)-1:0] m_axi_arprot,
|
||||
output wire [ (NUM_PORTS*4)-1:0] m_axi_arqos,
|
||||
output wire [ (NUM_PORTS*4)-1:0] m_axi_arregion,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_aruser,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_arvalid,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_arready,
|
||||
// AXI Read data channel
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_rid,
|
||||
input wire [ (NUM_PORTS*MEM_DATA_W)-1:0] m_axi_rdata,
|
||||
input wire [ (NUM_PORTS*2)-1:0] m_axi_rresp,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_rlast,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_ruser,
|
||||
input wire [ (NUM_PORTS*1)-1:0] m_axi_rvalid,
|
||||
output wire [ (NUM_PORTS*1)-1:0] m_axi_rready
|
||||
);
|
||||
|
||||
`include "rfnoc_block_replay_regs.vh"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Signal Declarations
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// CtrlPort Master
|
||||
wire ctrlport_req_wr;
|
||||
wire ctrlport_req_rd;
|
||||
wire [19:0] ctrlport_req_addr;
|
||||
wire [31:0] ctrlport_req_data;
|
||||
wire ctrlport_resp_ack;
|
||||
wire [31:0] ctrlport_resp_data;
|
||||
|
||||
// Data Stream to User Logic: in
|
||||
wire [NUM_PORTS*MEM_DATA_W*1-1:0] in_axis_tdata;
|
||||
wire [ NUM_PORTS-1:0] in_axis_tlast;
|
||||
wire [ NUM_PORTS-1:0] in_axis_tvalid;
|
||||
wire [ NUM_PORTS-1:0] in_axis_tready;
|
||||
|
||||
// Data Stream to User Logic: out
|
||||
wire [NUM_PORTS*MEM_DATA_W*1-1:0] out_axis_tdata;
|
||||
wire [ NUM_PORTS-1:0] out_axis_tlast;
|
||||
wire [ NUM_PORTS-1:0] out_axis_tvalid;
|
||||
wire [ NUM_PORTS-1:0] out_axis_tready;
|
||||
wire [ NUM_PORTS*64-1:0] out_axis_ttimestamp;
|
||||
wire [ NUM_PORTS-1:0] out_axis_thas_time;
|
||||
wire [ NUM_PORTS-1:0] out_axis_teob;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// NoC Shell
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
wire mem_rst_noc_shell;
|
||||
|
||||
noc_shell_replay #(
|
||||
.THIS_PORTID (THIS_PORTID),
|
||||
.CHDR_W (CHDR_W),
|
||||
.MEM_DATA_W (MEM_DATA_W),
|
||||
.MTU (MTU),
|
||||
.NUM_PORTS (NUM_PORTS)
|
||||
) noc_shell_replay_i (
|
||||
//---------------------
|
||||
// Framework Interface
|
||||
//---------------------
|
||||
|
||||
// Clock Inputs
|
||||
.rfnoc_chdr_clk (rfnoc_chdr_clk),
|
||||
.rfnoc_ctrl_clk (rfnoc_ctrl_clk),
|
||||
.mem_clk (mem_clk),
|
||||
// Reset Outputs
|
||||
.rfnoc_chdr_rst (),
|
||||
.rfnoc_ctrl_rst (),
|
||||
.mem_rst (mem_rst_noc_shell),
|
||||
// RFNoC Backend Interface
|
||||
.rfnoc_core_config (rfnoc_core_config),
|
||||
.rfnoc_core_status (rfnoc_core_status),
|
||||
// CHDR Input Ports (from framework)
|
||||
.s_rfnoc_chdr_tdata (s_rfnoc_chdr_tdata),
|
||||
.s_rfnoc_chdr_tlast (s_rfnoc_chdr_tlast),
|
||||
.s_rfnoc_chdr_tvalid (s_rfnoc_chdr_tvalid),
|
||||
.s_rfnoc_chdr_tready (s_rfnoc_chdr_tready),
|
||||
// CHDR Output Ports (to framework)
|
||||
.m_rfnoc_chdr_tdata (m_rfnoc_chdr_tdata),
|
||||
.m_rfnoc_chdr_tlast (m_rfnoc_chdr_tlast),
|
||||
.m_rfnoc_chdr_tvalid (m_rfnoc_chdr_tvalid),
|
||||
.m_rfnoc_chdr_tready (m_rfnoc_chdr_tready),
|
||||
// AXIS-Ctrl Input Port (from framework)
|
||||
.s_rfnoc_ctrl_tdata (s_rfnoc_ctrl_tdata),
|
||||
.s_rfnoc_ctrl_tlast (s_rfnoc_ctrl_tlast),
|
||||
.s_rfnoc_ctrl_tvalid (s_rfnoc_ctrl_tvalid),
|
||||
.s_rfnoc_ctrl_tready (s_rfnoc_ctrl_tready),
|
||||
// AXIS-Ctrl Output Port (to framework)
|
||||
.m_rfnoc_ctrl_tdata (m_rfnoc_ctrl_tdata),
|
||||
.m_rfnoc_ctrl_tlast (m_rfnoc_ctrl_tlast),
|
||||
.m_rfnoc_ctrl_tvalid (m_rfnoc_ctrl_tvalid),
|
||||
.m_rfnoc_ctrl_tready (m_rfnoc_ctrl_tready),
|
||||
|
||||
//---------------------
|
||||
// Client Interface
|
||||
//---------------------
|
||||
|
||||
// CtrlPort Clock and Reset
|
||||
.ctrlport_clk (),
|
||||
.ctrlport_rst (),
|
||||
// CtrlPort Master
|
||||
.m_ctrlport_req_wr (ctrlport_req_wr),
|
||||
.m_ctrlport_req_rd (ctrlport_req_rd),
|
||||
.m_ctrlport_req_addr (ctrlport_req_addr),
|
||||
.m_ctrlport_req_data (ctrlport_req_data),
|
||||
.m_ctrlport_resp_ack (ctrlport_resp_ack),
|
||||
.m_ctrlport_resp_data (ctrlport_resp_data),
|
||||
|
||||
// AXI-Stream Payload Context Clock and Reset
|
||||
.axis_data_clk (),
|
||||
.axis_data_rst (),
|
||||
// Data Stream to User Logic: in
|
||||
.m_in_axis_tdata (in_axis_tdata),
|
||||
.m_in_axis_tkeep (),
|
||||
.m_in_axis_tlast (in_axis_tlast),
|
||||
.m_in_axis_tvalid (in_axis_tvalid),
|
||||
.m_in_axis_tready (in_axis_tready),
|
||||
.m_in_axis_ttimestamp (),
|
||||
.m_in_axis_thas_time (),
|
||||
.m_in_axis_tlength (),
|
||||
.m_in_axis_teov (),
|
||||
.m_in_axis_teob (),
|
||||
// Data Stream from User Logic: out
|
||||
.s_out_axis_tdata (out_axis_tdata),
|
||||
.s_out_axis_tkeep ({NUM_PORTS*MEM_DATA_W/32{1'b1}}),
|
||||
.s_out_axis_tlast (out_axis_tlast),
|
||||
.s_out_axis_tvalid (out_axis_tvalid),
|
||||
.s_out_axis_tready (out_axis_tready),
|
||||
.s_out_axis_ttimestamp (out_axis_ttimestamp),
|
||||
.s_out_axis_thas_time (out_axis_thas_time),
|
||||
.s_out_axis_tlength ({NUM_PORTS{16'b0}}), // Not used when SIDEBAND_AT_END = 1
|
||||
.s_out_axis_teov ({NUM_PORTS{1'b0}}),
|
||||
.s_out_axis_teob (out_axis_teob)
|
||||
);
|
||||
|
||||
reg mem_rst;
|
||||
|
||||
// Combine the NoC Shell and AXI resets
|
||||
always @(posedge mem_clk) begin
|
||||
mem_rst <= axi_rst | mem_rst_noc_shell;
|
||||
end
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// CtrlPort Splitter
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
wire [ 1*NUM_PORTS-1:0] dec_ctrlport_req_wr;
|
||||
wire [ 1*NUM_PORTS-1:0] dec_ctrlport_req_rd;
|
||||
wire [20*NUM_PORTS-1:0] dec_ctrlport_req_addr;
|
||||
wire [32*NUM_PORTS-1:0] dec_ctrlport_req_data;
|
||||
wire [ 1*NUM_PORTS-1:0] dec_ctrlport_resp_ack;
|
||||
wire [32*NUM_PORTS-1:0] dec_ctrlport_resp_data;
|
||||
|
||||
generate
|
||||
if (NUM_PORTS > 1) begin : gen_ctrlport_decoder
|
||||
ctrlport_decoder #(
|
||||
.NUM_SLAVES (NUM_PORTS),
|
||||
.BASE_ADDR (0),
|
||||
.SLAVE_ADDR_W (REPLAY_ADDR_W)
|
||||
) ctrlport_decoder_i (
|
||||
.ctrlport_clk (mem_clk),
|
||||
.ctrlport_rst (mem_rst),
|
||||
.s_ctrlport_req_wr (ctrlport_req_wr),
|
||||
.s_ctrlport_req_rd (ctrlport_req_rd),
|
||||
.s_ctrlport_req_addr (ctrlport_req_addr),
|
||||
.s_ctrlport_req_data (ctrlport_req_data),
|
||||
.s_ctrlport_req_byte_en (4'hF),
|
||||
.s_ctrlport_req_has_time (1'b0),
|
||||
.s_ctrlport_req_time (64'b0),
|
||||
.s_ctrlport_resp_ack (ctrlport_resp_ack),
|
||||
.s_ctrlport_resp_status (),
|
||||
.s_ctrlport_resp_data (ctrlport_resp_data),
|
||||
.m_ctrlport_req_wr (dec_ctrlport_req_wr),
|
||||
.m_ctrlport_req_rd (dec_ctrlport_req_rd),
|
||||
.m_ctrlport_req_addr (dec_ctrlport_req_addr),
|
||||
.m_ctrlport_req_data (dec_ctrlport_req_data),
|
||||
.m_ctrlport_req_byte_en (),
|
||||
.m_ctrlport_req_has_time (),
|
||||
.m_ctrlport_req_time (),
|
||||
.m_ctrlport_resp_ack (dec_ctrlport_resp_ack),
|
||||
.m_ctrlport_resp_status ({NUM_PORTS{2'b0}}),
|
||||
.m_ctrlport_resp_data (dec_ctrlport_resp_data)
|
||||
);
|
||||
end else begin : gen_no_decoder
|
||||
assign dec_ctrlport_req_wr = ctrlport_req_wr;
|
||||
assign dec_ctrlport_req_rd = ctrlport_req_rd;
|
||||
assign dec_ctrlport_req_addr = {{20-REPLAY_ADDR_W{1'b0}},
|
||||
ctrlport_req_addr[REPLAY_ADDR_W-1:0]};
|
||||
assign dec_ctrlport_req_data = ctrlport_req_data;
|
||||
assign ctrlport_resp_ack = dec_ctrlport_resp_ack;
|
||||
assign ctrlport_resp_data = dec_ctrlport_resp_data;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Replay Block Instances
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Width of memory transfer count. Always 8 for AXI4.
|
||||
localparam MEM_COUNT_W = 8;
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i = 0; i < NUM_PORTS; i = i+1) begin : gen_replay_blocks
|
||||
|
||||
wire [ MEM_ADDR_W-1:0] write_addr;
|
||||
wire [MEM_COUNT_W-1:0] write_count;
|
||||
wire write_ctrl_valid;
|
||||
wire write_ctrl_ready;
|
||||
wire [ MEM_DATA_W-1:0] write_data;
|
||||
wire write_data_valid;
|
||||
wire write_data_ready;
|
||||
|
||||
wire [ MEM_ADDR_W-1:0] read_addr;
|
||||
wire [MEM_COUNT_W-1:0] read_count;
|
||||
wire read_ctrl_valid;
|
||||
wire read_ctrl_ready;
|
||||
wire [ MEM_DATA_W-1:0] read_data;
|
||||
wire read_data_valid;
|
||||
wire read_data_ready;
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Replay Handler
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
// This block implements the state machine and control logic for
|
||||
// recording and playback of data.
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
axis_replay #(
|
||||
.MEM_DATA_W (MEM_DATA_W),
|
||||
.MEM_ADDR_W (MEM_ADDR_W),
|
||||
.MEM_COUNT_W (MEM_COUNT_W)
|
||||
) axis_replay_i (
|
||||
.clk (mem_clk),
|
||||
.rst (mem_rst),
|
||||
|
||||
// CtrlPort Interface
|
||||
.s_ctrlport_req_wr (dec_ctrlport_req_wr [ 1*i +: 1]),
|
||||
.s_ctrlport_req_rd (dec_ctrlport_req_rd [ 1*i +: 1]),
|
||||
.s_ctrlport_req_addr (dec_ctrlport_req_addr [20*i +: 20]),
|
||||
.s_ctrlport_req_data (dec_ctrlport_req_data [32*i +: 32]),
|
||||
.s_ctrlport_resp_ack (dec_ctrlport_resp_ack [ 1*i +: 1]),
|
||||
.s_ctrlport_resp_data (dec_ctrlport_resp_data [32*i +: 32]),
|
||||
|
||||
// AXI Stream Interface
|
||||
//
|
||||
// Input
|
||||
.i_tdata (in_axis_tdata [MEM_DATA_W*i +: MEM_DATA_W]),
|
||||
.i_tvalid (in_axis_tvalid[ 1*i +: 1]),
|
||||
.i_tlast (in_axis_tlast [ 1*i +: 1]),
|
||||
.i_tready (in_axis_tready[ 1*i +: 1]),
|
||||
//
|
||||
// Output
|
||||
.o_tdata (out_axis_tdata [MEM_DATA_W*i +: MEM_DATA_W]),
|
||||
.o_ttimestamp (out_axis_ttimestamp[ 64*i +: 64]),
|
||||
.o_thas_time (out_axis_thas_time [ 1*i +: 1]),
|
||||
.o_teob (out_axis_teob [ 1*i +: 1]),
|
||||
.o_tvalid (out_axis_tvalid [ 1*i +: 1]),
|
||||
.o_tlast (out_axis_tlast [ 1*i +: 1]),
|
||||
.o_tready (out_axis_tready [ 1*i +: 1]),
|
||||
|
||||
// Memory Interface
|
||||
//
|
||||
// Write interface
|
||||
.write_addr (write_addr),
|
||||
.write_count (write_count),
|
||||
.write_ctrl_valid (write_ctrl_valid),
|
||||
.write_ctrl_ready (write_ctrl_ready),
|
||||
.write_data (write_data),
|
||||
.write_data_valid (write_data_valid),
|
||||
.write_data_ready (write_data_ready),
|
||||
//
|
||||
// Read interface
|
||||
.read_addr (read_addr),
|
||||
.read_count (read_count),
|
||||
.read_ctrl_valid (read_ctrl_valid),
|
||||
.read_ctrl_ready (read_ctrl_ready),
|
||||
.read_data (read_data),
|
||||
.read_data_valid (read_data_valid),
|
||||
.read_data_ready (read_data_ready)
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// AXI DMA Master
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
// This block translates simple read and write requests to AXI4
|
||||
// memory-mapped reads and writes for the RAM interface.
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
axi_dma_master #(
|
||||
.AWIDTH (MEM_ADDR_W),
|
||||
.DWIDTH (MEM_DATA_W)
|
||||
) axi_dma_master_i (
|
||||
//
|
||||
// AXI4 Memory Mapped Interface to DRAM
|
||||
//
|
||||
.aclk (mem_clk),
|
||||
.areset (mem_rst),
|
||||
|
||||
// Write control
|
||||
.m_axi_awid (m_axi_awid [ 1*i +: 1]),
|
||||
.m_axi_awaddr (m_axi_awaddr [MEM_ADDR_W*i +: MEM_ADDR_W]),
|
||||
.m_axi_awlen (m_axi_awlen [ 8*i +: 8]),
|
||||
.m_axi_awsize (m_axi_awsize [ 3*i +: 3]),
|
||||
.m_axi_awburst (m_axi_awburst [ 2*i +: 2]),
|
||||
.m_axi_awvalid (m_axi_awvalid [ 1*i +: 1]),
|
||||
.m_axi_awready (m_axi_awready [ 1*i +: 1]),
|
||||
.m_axi_awlock (m_axi_awlock [ 1*i +: 1]),
|
||||
.m_axi_awcache (m_axi_awcache [ 4*i +: 4]),
|
||||
.m_axi_awprot (m_axi_awprot [ 3*i +: 3]),
|
||||
.m_axi_awqos (m_axi_awqos [ 4*i +: 4]),
|
||||
.m_axi_awregion (m_axi_awregion[ 4*i +: 4]),
|
||||
.m_axi_awuser (m_axi_awuser [ 1*i +: 1]),
|
||||
|
||||
// Write Data
|
||||
.m_axi_wdata (m_axi_wdata [ MEM_DATA_W*i +: MEM_DATA_W]),
|
||||
.m_axi_wstrb (m_axi_wstrb [(MEM_DATA_W/8)*i +: (MEM_DATA_W/8)]),
|
||||
.m_axi_wlast (m_axi_wlast [ 1*i +: 1]),
|
||||
.m_axi_wvalid (m_axi_wvalid[ 1*i +: 1]),
|
||||
.m_axi_wready (m_axi_wready[ 1*i +: 1]),
|
||||
.m_axi_wuser (m_axi_wuser [ 1*i +: 1]),
|
||||
|
||||
// Write Response
|
||||
.m_axi_bid (m_axi_bid [1*i +: 1]),
|
||||
.m_axi_bresp (m_axi_bresp [2*i +: 2]),
|
||||
.m_axi_buser (m_axi_buser [1*i +: 1]),
|
||||
.m_axi_bvalid (m_axi_bvalid[1*i +: 1]),
|
||||
.m_axi_bready (m_axi_bready[1*i +: 1]),
|
||||
|
||||
// Read Control
|
||||
.m_axi_arid (m_axi_arid [ 1*i +: 1]),
|
||||
.m_axi_araddr (m_axi_araddr [MEM_ADDR_W*i +: MEM_ADDR_W]),
|
||||
.m_axi_arlen (m_axi_arlen [ 8*i +: 8]),
|
||||
.m_axi_arsize (m_axi_arsize [ 3*i +: 3]),
|
||||
.m_axi_arburst (m_axi_arburst [ 2*i +: 2]),
|
||||
.m_axi_arvalid (m_axi_arvalid [ 1*i +: 1]),
|
||||
.m_axi_arready (m_axi_arready [ 1*i +: 1]),
|
||||
.m_axi_arlock (m_axi_arlock [ 1*i +: 1]),
|
||||
.m_axi_arcache (m_axi_arcache [ 4*i +: 4]),
|
||||
.m_axi_arprot (m_axi_arprot [ 3*i +: 3]),
|
||||
.m_axi_arqos (m_axi_arqos [ 4*i +: 4]),
|
||||
.m_axi_arregion (m_axi_arregion[ 4*i +: 4]),
|
||||
.m_axi_aruser (m_axi_aruser [ 1*i +: 1]),
|
||||
|
||||
// Read Data
|
||||
.m_axi_rid (m_axi_rid [ 1*i +: 1]),
|
||||
.m_axi_rdata (m_axi_rdata [MEM_DATA_W*i +: MEM_DATA_W]),
|
||||
.m_axi_rresp (m_axi_rresp [ 2*i +: 2]),
|
||||
.m_axi_rlast (m_axi_rlast [ 1*i +: 1]),
|
||||
.m_axi_ruser (m_axi_ruser [ 1*i +: 1]),
|
||||
.m_axi_rvalid (m_axi_rvalid[ 1*i +: 1]),
|
||||
.m_axi_rready (m_axi_rready[ 1*i +: 1]),
|
||||
|
||||
//
|
||||
// Interface for Write transactions
|
||||
//
|
||||
.write_addr (write_addr),
|
||||
.write_count (write_count),
|
||||
.write_ctrl_valid (write_ctrl_valid),
|
||||
.write_ctrl_ready (write_ctrl_ready),
|
||||
.write_data (write_data),
|
||||
.write_data_valid (write_data_valid),
|
||||
.write_data_ready (write_data_ready),
|
||||
|
||||
//
|
||||
// Interface for Read transactions
|
||||
//
|
||||
.read_addr (read_addr),
|
||||
.read_count (read_count),
|
||||
.read_ctrl_valid (read_ctrl_valid),
|
||||
.read_ctrl_ready (read_ctrl_ready),
|
||||
.read_data (read_data),
|
||||
.read_data_valid (read_data_valid),
|
||||
.read_data_ready (read_data_ready),
|
||||
|
||||
//
|
||||
// Debug
|
||||
//
|
||||
.debug ()
|
||||
);
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule // rfnoc_block_replay
|
||||
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: rfnoc_block_replay_tb
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This testbench is the top-level testbench for the RFnoC Replay block. It
|
||||
// instantiates several different variants of the Replay testbench, each
|
||||
// using different parameters, to test different configurations.
|
||||
//
|
||||
|
||||
`default_nettype none
|
||||
|
||||
|
||||
module rfnoc_block_replay_all_tb;
|
||||
|
||||
`include "test_exec.svh"
|
||||
import PkgTestExec::*;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Test Definitions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
int CHDR_W;
|
||||
int ITEM_W;
|
||||
int NUM_PORTS;
|
||||
int MEM_DATA_W;
|
||||
int MEM_ADDR_W;
|
||||
int TEST_REGS;
|
||||
int TEST_FULL;
|
||||
int STALL_PROB;
|
||||
} test_config_t;
|
||||
|
||||
localparam NUM_TESTS = 15;
|
||||
|
||||
localparam test_config_t test[NUM_TESTS] = '{
|
||||
// Test different CHDR and memory widths:
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 32, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 1, STALL_PROB: 25},
|
||||
'{CHDR_W: 128, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 32, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 0, STALL_PROB: 25},
|
||||
'{CHDR_W: 256, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 32, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 1, STALL_PROB: 25},
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 2, MEM_DATA_W: 64, MEM_ADDR_W: 16, TEST_REGS: 1, TEST_FULL: 1, STALL_PROB: 25},
|
||||
'{CHDR_W: 128, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 64, MEM_ADDR_W: 16, TEST_REGS: 1, TEST_FULL: 0, STALL_PROB: 25},
|
||||
'{CHDR_W: 256, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 64, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 0, STALL_PROB: 25},
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 128, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 0, STALL_PROB: 25},
|
||||
'{CHDR_W: 128, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 128, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 0, STALL_PROB: 25},
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 256, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 1, STALL_PROB: 25},
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 1, MEM_DATA_W: 512, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 0, STALL_PROB: 25},
|
||||
// Test different stall probabilities:
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 2, MEM_DATA_W: 64, MEM_ADDR_W: 16, TEST_REGS: 1, TEST_FULL: 1, STALL_PROB: 0},
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 2, MEM_DATA_W: 64, MEM_ADDR_W: 16, TEST_REGS: 1, TEST_FULL: 1, STALL_PROB: 75},
|
||||
// Test large memory (> 32-bit) to check 64-bit registers:
|
||||
'{CHDR_W: 64, ITEM_W: 32, NUM_PORTS: 2, MEM_DATA_W: 64, MEM_ADDR_W: 34, TEST_REGS: 1, TEST_FULL: 0, STALL_PROB: 0},
|
||||
// Test different item widths to check time is handled correctly
|
||||
'{CHDR_W: 64, ITEM_W: 16, NUM_PORTS: 1, MEM_DATA_W: 32, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 1, STALL_PROB: 25},
|
||||
'{CHDR_W: 256, ITEM_W: 8, NUM_PORTS: 1, MEM_DATA_W: 32, MEM_ADDR_W: 16, TEST_REGS: 0, TEST_FULL: 1, STALL_PROB: 25}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// DUT Instances
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
genvar i;
|
||||
for (i = 0; i < NUM_TESTS; i++) begin : gen_test_config
|
||||
rfnoc_block_replay_tb #(
|
||||
.CHDR_W (test[i].CHDR_W ),
|
||||
.NUM_PORTS (test[i].NUM_PORTS ),
|
||||
.MEM_DATA_W (test[i].MEM_DATA_W),
|
||||
.MEM_ADDR_W (test[i].MEM_ADDR_W),
|
||||
.TEST_FULL (test[i].TEST_FULL )
|
||||
) rfnoc_block_replay_tb_i ();
|
||||
end : gen_test_config
|
||||
|
||||
endmodule : rfnoc_block_replay_all_tb
|
||||
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
//
|
||||
// Module: rfnoc_block_replay_regs (Header)
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// This is a header file that contains the register descriptions for the
|
||||
// RFNoC Replay block.
|
||||
//
|
||||
// Each RFNoC Replay block consists of NUM_PORTS independent replay engines.
|
||||
// Each one has its own address space that is REPLAY_ADDR_W bits wide. That
|
||||
// is, replay block N can be addressed starting at byte offset
|
||||
// N*(2**REPLAY_ADDR_W).
|
||||
//
|
||||
// All 64-bit registers should be read/written least-significant word first
|
||||
// to guarantee coherence.
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Register Space
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// The amount of address space taken up by each replay engine. That is, the
|
||||
// address space for port N starts at N*(2^REPLAY_ADDR_W).
|
||||
localparam REPLAY_ADDR_W = 20'h00008;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Replay Register Descriptions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// REG_COMPAT (R)
|
||||
//
|
||||
// Compatibility version. This read-only register is used by software to
|
||||
// determine if this block's version is compatible with the running software. A
|
||||
// major version change indicates the software for the previous major version
|
||||
// is no longer compatible. A minor version change means the previous version
|
||||
// is compatible, but some new features may be unavailable.
|
||||
//
|
||||
// [31:16] Major version
|
||||
// [15: 0] Minor version
|
||||
//
|
||||
localparam REG_COMPAT = 'h00;
|
||||
//
|
||||
localparam REG_MAJOR_POS = 16;
|
||||
localparam REG_MAJOR_LEN = 16;
|
||||
//
|
||||
localparam REG_MINOR_POS = 0;
|
||||
localparam REG_MINOR_LEN = 16;
|
||||
|
||||
// REG_MEM_SIZE (R)
|
||||
//
|
||||
// Returns information about the size of the attached memory. The address size
|
||||
// allows software to determine what buffer size and base address values are
|
||||
// valid.
|
||||
//
|
||||
// [31:16] : Memory Data Word Size. Returns the bit width of the RAM word size.
|
||||
// [15: 0] : Memory Address Size. Returns the bit width of the RAM byte
|
||||
// address. That is, the memory is 2**VALUE bytes in size.
|
||||
//
|
||||
localparam REG_MEM_SIZE = 'h04;
|
||||
//
|
||||
localparam REG_DATA_SIZE_LEN = 16;
|
||||
localparam REG_DATA_SIZE_POS = 16;
|
||||
//
|
||||
localparam REG_ADDR_SIZE_LEN = 16;
|
||||
localparam REG_ADDR_SIZE_POS = 0;
|
||||
|
||||
// REG_REC_RESTART (W)
|
||||
//
|
||||
// Record Buffer Restart Register. Software must write to this register after
|
||||
// updating the base address or buffer size. This will cause recording to
|
||||
// restart at the indicated location. It does not matter what value you write.
|
||||
//
|
||||
localparam REG_REC_RESTART = 'h08;
|
||||
|
||||
// REG_REC_BASE_ADDR (R/W)
|
||||
//
|
||||
// Record Base Address Register. This is the byte address that controls where
|
||||
// in the attached memory that recorded data should be stored. This must be a
|
||||
// multiple of memory word size (REG_DATA_SIZE) in bytes.
|
||||
//
|
||||
localparam REG_REC_BASE_ADDR_LO = 'h10;
|
||||
localparam REG_REC_BASE_ADDR_HI = 'h14;
|
||||
|
||||
// REG_REC_BUFFER_SIZE (R/W)
|
||||
//
|
||||
// Record Buffer Size Register. This controls the portion of the RAM allocated
|
||||
// to the record buffer, in bytes. This must be a multiple of memory word size
|
||||
// (REG_DATA_SIZE) in bytes.
|
||||
//
|
||||
localparam REG_REC_BUFFER_SIZE_LO = 'h18;
|
||||
localparam REG_REC_BUFFER_SIZE_HI = 'h1C;
|
||||
|
||||
// REG_REC_FULLNESS (R)
|
||||
//
|
||||
// Record Fullness. Returns the number of bytes that have been recorded in the
|
||||
// record buffer.
|
||||
//
|
||||
// This is is a 64-bit register in which the least-significant 32-bit word must
|
||||
// be read first.
|
||||
//
|
||||
localparam REG_REC_FULLNESS_LO = 'h20;
|
||||
localparam REG_REC_FULLNESS_HI = 'h24;
|
||||
|
||||
// REG_PLAY_BASE_ADDR (R/W)
|
||||
//
|
||||
// Playback Base Address Register. This is the byte address that controls where
|
||||
// in the attached memory to read the data to be played back. This must be a
|
||||
// multiple of memory word size (REG_DATA_SIZE) in bytes.
|
||||
//
|
||||
localparam REG_PLAY_BASE_ADDR_LO = 'h28;
|
||||
localparam REG_PLAY_BASE_ADDR_HI = 'h2C;
|
||||
|
||||
// REG_PLAY_BUFFER_SIZE (R/W)
|
||||
//
|
||||
// Playback Buffer Size Register. This controls the size, in bytes, of the
|
||||
// playback buffer in the attached memory. This must be a multiple of memory
|
||||
// word size (REG_DATA_SIZE) in bytes.
|
||||
//
|
||||
localparam REG_PLAY_BUFFER_SIZE_LO = 'h30;
|
||||
localparam REG_PLAY_BUFFER_SIZE_HI = 'h34;
|
||||
|
||||
// REG_PLAY_CMD_NUM_WORDS (R/W)
|
||||
//
|
||||
// Playback Command Number of Words. This register controls the number of
|
||||
// memory data words to play back.
|
||||
//
|
||||
localparam REG_PLAY_CMD_NUM_WORDS_LO = 'h38;
|
||||
localparam REG_PLAY_CMD_NUM_WORDS_HI = 'h3C;
|
||||
//
|
||||
localparam REG_CMD_NUM_WORDS_LEN = 64;
|
||||
|
||||
// REG_PLAY_CMD_TIME (R/W)
|
||||
//
|
||||
// Playback Command Time. This register indicates the timestamp to attach to
|
||||
// the first packet that is played back, if timed playback is enabled.
|
||||
// Subsequent packets will have the correctly incremented timestamp attached.
|
||||
//
|
||||
localparam REG_PLAY_CMD_TIME_LO = 'h40;
|
||||
localparam REG_PLAY_CMD_TIME_HI = 'h44;
|
||||
//
|
||||
localparam REG_CMD_TIME_LEN = 64;
|
||||
|
||||
// REG_PLAY_CMD (W)
|
||||
//
|
||||
// Playback 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.
|
||||
//
|
||||
// [31] : Timed flag. Indicates if the command is timed (1) or not (0).
|
||||
//
|
||||
// [1:0] : Command field. The command indicates what you want the playback to
|
||||
// do. It can be one of the following:
|
||||
//
|
||||
// 0 (PLAY_CMD_STOP) : Stop playing back data
|
||||
// 1 (PLAY_CMD_FINITE) : Acquire NUM_SAMPS then stop
|
||||
// 2 (PLAY_CMD_CONTINUOUS) : Play back continuously until stopped.
|
||||
//
|
||||
localparam REG_PLAY_CMD = 'h48;
|
||||
//
|
||||
localparam REG_PLAY_TIMED_POS = 31;
|
||||
localparam REG_PLAY_TIMED_LEN = 1;
|
||||
//
|
||||
localparam REG_PLAY_CMD_POS = 0;
|
||||
localparam REG_PLAY_CMD_LEN = 2;
|
||||
|
||||
// REG_PLAY_WORDS_PER_PKT (R/W)
|
||||
//
|
||||
// [15:0] Words Per Packet. This registers controls how many memory data words
|
||||
// (REG_DATA_SIZE bits each) are inserted into each packet during
|
||||
// playback. Effectively, it controls the samples-per-packet (SPP), but
|
||||
// the replay block is sample-size agnostic.
|
||||
//
|
||||
// This value should never be set such that the total RFNoC packet size
|
||||
// would exceed the system MTU or the maximum packet size allowed by
|
||||
// RFNoC (2^16 bytes). Also note that the last packet of a command may
|
||||
// be less than this size.
|
||||
//
|
||||
localparam REG_PLAY_WORDS_PER_PKT = 'h4C;
|
||||
//
|
||||
localparam REG_PLAY_WORDS_PER_PKT_LEN = 16;
|
||||
//
|
||||
localparam REG_PLAY_WORDS_PER_PKT_INIT = 160;
|
||||
|
||||
// REG_PLAY_ITEM_SIZE (R/W)
|
||||
//
|
||||
// [7:0] Number of bytes per item. This controls how much time is incremented
|
||||
// for each memory word of data. This must be a power of 2.
|
||||
//
|
||||
localparam REG_PLAY_ITEM_SIZE = 'h50;
|
||||
//
|
||||
localparam REG_ITEM_SIZE_POS = 0;
|
||||
localparam REG_ITEM_SIZE_LEN = 8;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Playback Commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
localparam PLAY_CMD_STOP = 2'h0;
|
||||
localparam PLAY_CMD_FINITE = 2'h1;
|
||||
localparam PLAY_CMD_CONTINUOUS = 2'h2;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -231,7 +231,6 @@ module axis_data_to_chdr #(
|
||||
wire in_pyld_tlast;
|
||||
wire in_pyld_tvalid;
|
||||
wire in_pyld_tready;
|
||||
wire width_conv_tready;
|
||||
|
||||
wire [CHDR_W-1:0] out_pyld_tdata;
|
||||
wire out_pyld_tlast;
|
||||
@@ -368,12 +367,6 @@ module axis_data_to_chdr #(
|
||||
endgenerate
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// This state machine prevents data from transferring when the pkt_info_fifo
|
||||
// is stalled. This ensures that we don't overflow the pkt_info_fifo.
|
||||
always @(posedge axis_chdr_clk) begin
|
||||
|
||||
Reference in New Issue
Block a user