aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/blocks
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/blocks')
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/axis_replay.v164
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_regs.vh20
-rw-r--r--fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_tb.sv132
3 files changed, 266 insertions, 50 deletions
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/axis_replay.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/axis_replay.v
index e30ee81e2..194aed3e9 100644
--- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/axis_replay.v
+++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/axis_replay.v
@@ -32,7 +32,8 @@
// writing a command to the REG_PLAY_CMD register. The play command indicates
// if it should play a fixed number of words then stop (PLAY_CMD_FINITE),
// playback forever (PLAY_CMD_CONTINUOUS), or stop playback (PLAY_CMD_STOP).
-// The number of words to play back with PLAY_CMD_FINITE is set by first
+// The beginning of the playback is set by first writing to
+// REG_PLAY_BASE_ADDR. The number of words to play back is set by first
// writing to REG_PLAY_CMD_NUM_WORDS.
//
// The length of the packets generated during playback is configured by the
@@ -40,9 +41,7 @@
//
// A timestamp for playback can also be specified by setting
// REG_PLAY_CMD_TIME and setting the REG_PLAY_TIMED_POS bit as part of the
-// command write. The timestamp will then be included in all output packets,
-// starting with the provided timestamp value and auto-incrementing by one
-// for every REG_ITEM_SIZE bytes of data in each packet.
+// command write. The timestamp will be included in the first output packet.
//
// When playback reaches the end of the configured playback buffer, if more
// words were requested, it will loop back to the beginning of the buffer to
@@ -150,7 +149,7 @@ module axis_replay #(
//---------------------------------------------------------------------------
localparam [REG_MAJOR_LEN-1:0] COMPAT_MAJOR = 1;
- localparam [REG_MINOR_LEN-1:0] COMPAT_MINOR = 0;
+ localparam [REG_MINOR_LEN-1:0] COMPAT_MINOR = 1;
localparam [REG_ITEM_SIZE_LEN-1:0] DEFAULT_ITEM_SIZE = 4; // 4 bytes for sc16
@@ -240,20 +239,26 @@ module axis_replay #(
reg [MEM_ADDR_W-1:0] reg_rec_base_addr;
reg [MEM_SIZE_W-1:0] reg_rec_buffer_size;
reg [31:0] reg_rec_fullness_hi;
+ reg [31:0] reg_rec_pos_hi;
reg rec_restart;
reg [MEM_ADDR_W-1:0] reg_play_base_addr;
reg [MEM_SIZE_W-1:0] reg_play_buffer_size;
+ reg [31:0] reg_play_pos_hi;
reg [NUM_WORDS_W-1:0] reg_play_cmd_num_words;
reg [TIME_W-1:0] reg_play_cmd_time;
reg [CMD_W-1:0] reg_play_cmd;
reg reg_play_cmd_timed;
reg reg_play_cmd_valid;
+ wire reg_play_cmd_ready;
reg play_cmd_stop;
reg clear_cmd_fifo;
reg [WPP_W-1:0] reg_play_words_per_pkt = REG_PLAY_WORDS_PER_PKT_INIT;
reg [REG_ITEM_SIZE_LEN-1:0] reg_item_size = DEFAULT_ITEM_SIZE;
+ wire [5:0] reg_cmd_fifo_space;
wire [63:0] reg_rec_fullness;
+ wire [63:0] reg_rec_pos;
+ wire [63:0] reg_play_pos;
reg rec_restart_clear;
reg play_cmd_stop_ack;
@@ -275,8 +280,10 @@ module axis_replay #(
reg_rec_base_addr <= 0;
reg_rec_buffer_size <= 0;
reg_rec_fullness_hi <= 'bX;
+ reg_rec_pos_hi <= 'bX;
reg_play_base_addr <= 0;
reg_play_buffer_size <= 0;
+ reg_play_pos_hi <= 'bX;
reg_play_cmd_num_words <= 0;
reg_play_cmd_time <= 0;
reg_play_words_per_pkt <= REG_PLAY_WORDS_PER_PKT_INIT;
@@ -379,13 +386,46 @@ module axis_replay #(
REG_PLAY_ITEM_SIZE :
s_ctrlport_resp_data[REG_ITEM_SIZE_POS+:REG_ITEM_SIZE_LEN]
<= reg_item_size;
+ REG_REC_POS_LO : begin
+ s_ctrlport_resp_data <= reg_rec_pos[31:0];
+ if (MEM_SIZE_W > 32) begin
+ // The LO register must be read first. Save HI part now to
+ // guarantee coherence when HI register is read.
+ reg_rec_pos_hi <= 0;
+ reg_rec_pos_hi[0 +: max(MEM_SIZE_W-32, 1)]
+ <= reg_rec_pos[32 +: max(MEM_SIZE_W-32, 1)];
+ end
+ end
+ REG_REC_POS_HI :
+ if (MEM_SIZE_W > 32) begin
+ // Return the saved value to guarantee coherence
+ s_ctrlport_resp_data <= reg_rec_pos_hi;
+ end
+ REG_PLAY_POS_LO : begin
+ s_ctrlport_resp_data <= reg_play_pos[31:0];
+ if (MEM_SIZE_W > 32) begin
+ // The LO register must be read first. Save HI part now to
+ // guarantee coherence when HI register is read.
+ reg_play_pos_hi <= 0;
+ reg_play_pos_hi[0 +: max(MEM_SIZE_W-32, 1)]
+ <= reg_play_pos[32 +: max(MEM_SIZE_W-32, 1)];
+ end
+ end
+ REG_PLAY_POS_HI :
+ if (MEM_SIZE_W > 32) begin
+ // Return the saved value to guarantee coherence
+ s_ctrlport_resp_data <= reg_play_pos_hi;
+ end
+ REG_PLAY_CMD_FIFO_SPACE :
+ s_ctrlport_resp_data[5:0] <= reg_cmd_fifo_space;
endcase
+ end
//-----------------------------------------
// Register Writes
//-----------------------------------------
- end else if (s_ctrlport_req_wr) begin
+ if (s_ctrlport_req_wr) begin
s_ctrlport_resp_ack <= 1;
case (s_ctrlport_req_addr)
REG_REC_BASE_ADDR_LO :
@@ -473,23 +513,25 @@ module axis_replay #(
wire cmd_timed_cf;
wire [NUM_WORDS_W-1:0] cmd_num_words_cf;
wire [TIME_W-1:0] cmd_time_cf;
+ wire [MEM_ADDR_W-1:0] cmd_base_addr_cf;
+ wire [MEM_SIZE_W-1:0] cmd_buffer_size_cf;
wire cmd_fifo_valid;
reg cmd_fifo_ready;
axi_fifo_short #(
- .WIDTH (1 + CMD_W + NUM_WORDS_W + TIME_W)
+ .WIDTH (MEM_ADDR_W + MEM_SIZE_W + 1 + CMD_W + NUM_WORDS_W + TIME_W)
) command_fifo (
.clk (clk),
.reset (rst),
.clear (clear_cmd_fifo),
- .i_tdata ({reg_play_cmd_timed, reg_play_cmd, reg_play_cmd_num_words, reg_play_cmd_time}),
+ .i_tdata ({play_base_addr_sr, play_buffer_size_sr, reg_play_cmd_timed, reg_play_cmd, reg_play_cmd_num_words, reg_play_cmd_time}),
.i_tvalid (reg_play_cmd_valid),
- .i_tready (),
- .o_tdata ({cmd_timed_cf, cmd_cf, cmd_num_words_cf, cmd_time_cf}),
+ .i_tready (reg_play_cmd_ready),
+ .o_tdata ({cmd_base_addr_cf, cmd_buffer_size_cf, cmd_timed_cf, cmd_cf, cmd_num_words_cf, cmd_time_cf}),
.o_tvalid (cmd_fifo_valid),
.o_tready (cmd_fifo_ready),
.occupied (),
- .space ()
+ .space (reg_cmd_fifo_space)
);
@@ -553,6 +595,7 @@ module axis_replay #(
reg rec_wait_timeout;
assign reg_rec_fullness = rec_buffer_used * BYTES_PER_WORD;
+ assign reg_rec_pos = rec_addr;
always @(posedge clk) begin
if (rst) begin
@@ -564,7 +607,7 @@ module axis_replay #(
rec_buffer_used <= 0;
// Don't care:
- rec_addr <= {MEM_ADDR_W{1'bX}};
+ rec_addr <= {MEM_ADDR_W{1'b0}};
rec_size_0 <= {MEM_ADDR_W{1'bX}};
rec_size <= {MEM_ADDR_W{1'bX}};
write_count <= {MEM_COUNT_W{1'bX}};
@@ -706,16 +749,17 @@ module axis_replay #(
// FSM States
localparam PLAY_IDLE = 0;
- localparam PLAY_WAIT_DATA_READY = 1;
- localparam PLAY_CHECK_ALIGN = 2;
- localparam PLAY_SIZE_CALC = 3;
- localparam PLAY_MEM_REQ = 4;
- localparam PLAY_WAIT_MEM_START = 5;
- localparam PLAY_WAIT_MEM_COMMIT = 6;
- localparam PLAY_DONE_CHECK = 7;
+ localparam PLAY_CHECK_SIZES = 1;
+ localparam PLAY_WAIT_DATA_READY = 2;
+ localparam PLAY_CHECK_ALIGN = 3;
+ localparam PLAY_SIZE_CALC = 4;
+ localparam PLAY_MEM_REQ = 5;
+ localparam PLAY_WAIT_MEM_START = 6;
+ localparam PLAY_WAIT_MEM_COMMIT = 7;
+ localparam PLAY_DONE_CHECK = 8;
// State Signals
- reg [2:0] play_state;
+ reg [3:0] play_state;
// Registers
reg [MEM_ADDR_W-1:0] play_addr; // Current byte offset into record buffer
@@ -729,13 +773,14 @@ module axis_replay #(
//
reg [NUM_WORDS_W-1:0] play_words_remaining; // Number of words left for playback command
reg [CMD_W-1:0] cmd; // Copy of cmd_cf from last command
- reg cmd_timed; // Copy of cmd_timed_cf from last command
- reg [TIME_W-1:0] cmd_time; // Copy of cmd_time_cf from last command
+ reg [MEM_ADDR_W-1:0] cmd_base_addr; // Copy of cmd_base_addr_cf from last command
+ reg [MEM_SIZE_W-1:0] cmd_buffer_size; // Copy of cmd_buffer_size_cf from last command
reg last_trans; // Is this the last read transaction for the command?
reg play_full_burst_avail; // True if we there's a full burst to read
- reg play_buffer_avail_nonzero; // True if play_buffer_avail > 0
reg next_read_size_ok; // True if it's OK to read next_read_size
+ reg play_buffer_zero; // True if play buffer size is zero
+ reg num_words_zero; // True if number of words to play is zero
reg [MEM_ADDR_W-1:0] next_read_size_m1; // next_read_size - 1
reg [MEM_ADDR_W-1:0] play_words_remaining_m1; // play_words_remaining - 1
@@ -745,21 +790,23 @@ module axis_replay #(
reg pause_data_transfer;
+ assign reg_play_pos = play_addr;
+
always @(posedge clk)
begin
if (rst) begin
play_state <= PLAY_IDLE;
cmd_fifo_ready <= 1'b0;
+ play_addr <= {MEM_ADDR_W{1'b0}};
+ last_trans <= 1'b0;
// Don't care:
play_full_burst_avail <= 1'bX;
- play_buffer_avail_nonzero <= 1'bX;
play_buffer_end <= {MEM_SIZE_W{1'bX}};
read_ctrl_valid <= 1'bX;
- play_addr <= {MEM_ADDR_W{1'bX}};
cmd <= {CMD_W{1'bX}};
- cmd_time <= {TIME_W{1'bX}};
- cmd_timed <= 1'bX;
+ cmd_base_addr <= {MEM_ADDR_W{1'bX}};
+ cmd_buffer_size <= {MEM_SIZE_W{1'bX}};
play_buffer_avail <= {MEM_SIZE_W{1'bX}};
play_size_aligned <= {MEM_SIZE_W{1'bX}};
play_words_remaining <= {NUM_WORDS_W{1'bX}};
@@ -773,14 +820,13 @@ module axis_replay #(
play_addr_0 <= {MEM_ADDR_W+1{1'bX}};
play_buffer_avail_0 <= {MEM_SIZE_W{1'bX}};
play_addr_1 <= {MEM_ADDR_W{1'bX}};
- last_trans <= 1'b0;
+ play_buffer_zero <= 1'bX;
+ num_words_zero <= 1'bX;
end else begin
// Calculate how many words are left to read from the record buffer
play_full_burst_avail <= (play_buffer_avail >= MEM_BURST_LEN);
- play_buffer_avail_nonzero <= (play_buffer_avail > 0);
- play_buffer_end <= play_base_addr_sr + play_buffer_size_sr;
play_size_aligned <= AXI_ALIGNMENT - ((play_addr/BYTES_PER_WORD) & (AXI_ALIGNMENT-1));
@@ -794,28 +840,43 @@ module axis_replay #(
//
case (play_state)
PLAY_IDLE : begin
- // Always start reading at the start of the record buffer
- play_addr <= play_base_addr_sr;
+ // Save needed command info
+ cmd <= cmd_cf;
+ cmd_base_addr <= cmd_base_addr_cf;
+ cmd_buffer_size <= cmd_buffer_size_cf / BYTES_PER_WORD;
- // Save off command info
- if (cmd_cf == PLAY_CMD_CONTINUOUS)
+ // Initialize the play variables
+ if (cmd_cf == PLAY_CMD_CONTINUOUS) begin
play_words_remaining <= MEM_BURST_LEN;
- else
+ num_words_zero <= 0;
+ end else begin
play_words_remaining <= cmd_num_words_cf;
- cmd_timed <= cmd_timed_cf;
- cmd_time <= cmd_time_cf;
- cmd <= cmd_cf;
-
- // Save the buffer info so it doesn't update during playback
- play_buffer_avail <= play_buffer_size_sr / BYTES_PER_WORD;
+ num_words_zero <= (cmd_num_words_cf == 0);
+ end
+ play_buffer_avail <= cmd_buffer_size_cf / BYTES_PER_WORD;
+ play_buffer_end <= {1'b0, cmd_base_addr_cf} + cmd_buffer_size_cf;
+ play_buffer_zero <= (cmd_buffer_size_cf == 0);
- // Wait until we receive a command and we have enough data recorded
- // to honor it.
+ // Wait until we receive a command
if (play_cmd_stop) begin
play_cmd_stop_ack <= 1'b1;
- end else if (cmd_fifo_valid && play_buffer_avail_nonzero) begin
+ end else if (cmd_fifo_valid) begin
+ // Only update the play address when valid so readback is accurate
+ play_addr <= cmd_base_addr_cf;
+
// Dequeue the command from the FIFO
cmd_fifo_ready <= 1'b1;
+
+ play_state <= PLAY_CHECK_SIZES;
+ end
+ end
+
+ PLAY_CHECK_SIZES : begin
+ // Check buffer and num_word sizes and allow propagation of
+ // play_full_burst_avail.
+ if (play_buffer_zero | num_words_zero) begin
+ play_state <= PLAY_IDLE;
+ end else begin
play_state <= PLAY_WAIT_DATA_READY;
end
end
@@ -902,18 +963,21 @@ module axis_replay #(
// signals that the interface has received a response for the whole
// read transaction.
if (read_ctrl_ready) begin
+ // Check if this is the last transaction.
+ if (last_trans) begin
+ play_addr_1 <= play_addr_0[MEM_ADDR_W-1:0];
+ play_buffer_avail <= 0;
+
// 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 / BYTES_PER_WORD;
+ end else if (play_addr_0 >= play_buffer_end) begin
+ play_addr_1 <= cmd_base_addr;
+ play_buffer_avail <= cmd_buffer_size;
+
end else begin
play_addr_1 <= play_addr_0[MEM_ADDR_W-1:0];
play_buffer_avail <= play_buffer_avail_0;
end
- // Update the time for the first word of the next transaction
- cmd_time <= cmd_time + (read_count + 1) * (MEM_DATA_W/32);
-
play_state <= PLAY_DONE_CHECK;
end
end
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_regs.vh b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_regs.vh
index 4849da47f..a04c9f231 100644
--- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_regs.vh
+++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_regs.vh
@@ -196,6 +196,26 @@ localparam REG_PLAY_ITEM_SIZE = 'h50;
localparam REG_ITEM_SIZE_POS = 0;
localparam REG_ITEM_SIZE_LEN = 8;
+// REG_REC_POS (R)
+//
+// Returns the byte address of the record pointer.
+//
+localparam REG_REC_POS_LO = 'h54;
+localparam REG_REC_POS_HI = 'h58;
+
+// REG_PLAY_POS (R)
+//
+// Returns the byte address of the play pointer.
+//
+localparam REG_PLAY_POS_LO = 'h5C;
+localparam REG_PLAY_POS_HI = 'h60;
+
+// REG_PLAY_CMD_FIFO_SPACE (R)
+//
+// Returns remaining space in the command FIFO
+//
+localparam REG_PLAY_CMD_FIFO_SPACE = 'h64;
+
//-----------------------------------------------------------------------------
// Playback Commands
//-----------------------------------------------------------------------------
diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_tb.sv
index 5674a3cf6..d4cb071cf 100644
--- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_tb.sv
+++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_replay/rfnoc_block_replay_tb.sv
@@ -476,6 +476,30 @@ module rfnoc_block_replay_tb#(
endtask : wait_record_fullness
+ // Validate record position
+ task automatic validate_record_position(
+ input int port,
+ input longint position
+ );
+ logic [63:0] value;
+
+ read_reg_64(port, REG_REC_POS_LO, value);
+ `ASSERT_ERROR(value == position, $sformatf("Record position expected at 0x%h, but at 0x%h", position, value));
+ endtask : validate_record_position
+
+
+ // Validate record position
+ task automatic validate_play_position(
+ input int port,
+ input longint position
+ );
+ logic [63:0] value;
+
+ read_reg_64(port, REG_PLAY_POS_LO, value);
+ `ASSERT_ERROR(value == position, $sformatf("Play position expected at 0x%h, but at 0x%h", position, value));
+ endtask : validate_play_position
+
+
// Make sure nothing is received until the timeout has elapsed
task automatic check_rx_idle(
input int port,
@@ -863,6 +887,10 @@ module rfnoc_block_replay_tb#(
(32'(MEM_ADDR_W) << REG_ADDR_SIZE_POS)
);
test_read_reg(port, REG_REC_FULLNESS_LO, 64);
+ test_read_reg(port, REG_PLAY_ITEM_SIZE, 32, 4);
+ test_read_reg(port, REG_REC_POS_LO, 64);
+ test_read_reg(port, REG_PLAY_POS_LO, 64);
+ test_read_reg(port, REG_PLAY_CMD_FIFO_SPACE, 32, 32);
// The following registers are write only and aren't tested here.
// REG_REC_RESTART - Tested during every record operation
@@ -1640,6 +1668,109 @@ module rfnoc_block_replay_tb#(
//---------------------------------------------------------------------------
+ // Test Record and Play position
+ //---------------------------------------------------------------------------
+ //
+ // Test record and play positions advance properly. Checks position after
+ // recording and playing each packet and checks proper position during wraps.
+ //
+ //---------------------------------------------------------------------------
+
+ task test_position(int port = 0);
+ item_t send_items[$];
+ item_t recv_items[$];
+ int num_items, num_packets;
+ longint unsigned mem_size;
+ logic [63:0] val64;
+
+ test.start_test("Test record and play positions", 2ms);
+
+ mem_size = 2**MEM_ADDR_W; // Memory size in bytes
+ num_items = 2**$clog2(SPP); // Pick a power of 2 near SPP
+ num_packets = 5;
+
+ // Set up the record buffer
+ write_reg_64(port, REG_REC_BASE_ADDR_LO, 0);
+ write_reg_64(port, REG_REC_BUFFER_SIZE_LO, num_packets*num_items*ITEM_SIZE);
+ write_reg (port, REG_REC_RESTART, 0);
+
+ // Fill the buffer and validate the record position after each packet.
+ for (int i = 0; i < num_packets; i++) begin
+ // Send a different random sequence for each packet
+ send_items = gen_test_data(num_items, i*num_items);
+ blk_ctrl.send_items(port, send_items);
+ wait_record_fullness(port, (i+1)*num_items*ITEM_SIZE);
+ validate_record_position(port, ((i+1)*num_items*ITEM_SIZE));
+ end
+
+ // Send one additional packet to ensure the position does not advance
+ send_items = gen_test_data(num_items, num_packets*num_items);
+ blk_ctrl.send_items(port, send_items);
+
+ // Give extra time for the last packet
+ #(CHDR_CLK_PER * num_items * 20);
+
+ // Make sure the position has not advanced and the fullness has not changed
+ validate_record_position(port, num_packets*num_items*ITEM_SIZE);
+ read_reg_64(port, REG_REC_FULLNESS_LO, val64);
+ `ASSERT_ERROR(val64 == num_packets*num_items*ITEM_SIZE, "Memory fullness is not correct");
+
+ // Play back the data one packet at a time and validate play position
+ write_reg(port, REG_PLAY_WORDS_PER_PKT, num_items*ITEM_SIZE/MEM_WORD_SIZE);
+ write_reg_64(port, REG_PLAY_CMD_NUM_WORDS_LO, num_items*ITEM_SIZE/MEM_WORD_SIZE);
+ write_reg_64(port, REG_PLAY_BUFFER_SIZE_LO, num_items*ITEM_SIZE);
+ for (int i = 0; i < num_packets; i++) begin
+ write_reg_64(port, REG_PLAY_BASE_ADDR_LO, i*num_items*ITEM_SIZE);
+ write_reg(port, REG_PLAY_CMD, PLAY_CMD_FINITE);
+ send_items = gen_test_data(num_items, i*num_items);
+ blk_ctrl.recv_items(port, recv_items);
+ `ASSERT_ERROR(
+ ChdrData#(CHDR_W, ITEM_W)::item_equal(send_items, recv_items),
+ "Playback data did not match"
+ );
+ validate_play_position(port, ((i+1)*num_items*ITEM_SIZE));
+ end
+
+ // Restart recording to get the extra packet we sent at the beginning
+ // to validate the record position wraps.
+ write_reg(port, REG_REC_RESTART, 0);
+ wait_record_fullness(port, num_items*ITEM_SIZE);
+ validate_record_position(port, num_items*ITEM_SIZE);
+
+ // Playback the new data, which should continue the values from the last
+ // record operation.
+ write_reg_64(port, REG_PLAY_BASE_ADDR_LO, 0);
+ write_reg_64(port, REG_PLAY_BUFFER_SIZE_LO, num_items*ITEM_SIZE);
+ write_reg_64(port, REG_PLAY_CMD_NUM_WORDS_LO, num_items*ITEM_SIZE/MEM_WORD_SIZE);
+ write_reg(port, REG_PLAY_CMD, PLAY_CMD_FINITE);
+ send_items = gen_test_data(num_items, num_packets*num_items);
+ blk_ctrl.recv_items(port, recv_items);
+ `ASSERT_ERROR(
+ ChdrData#(CHDR_W, ITEM_W)::item_equal(send_items, recv_items),
+ "Playback data did not match"
+ );
+ validate_play_position(port, num_items*ITEM_SIZE);
+
+ // Test the play wrap. Play num_packets plus one and validate position.
+ // This is done at the end of the memory space to test the wrap within the
+ // buffer space as well as the wrap at the end of the memory space.
+ write_reg_64(port, REG_PLAY_BASE_ADDR_LO, mem_size-(num_packets*num_items*ITEM_SIZE));
+ write_reg_64(port, REG_PLAY_BUFFER_SIZE_LO, num_packets*num_items*ITEM_SIZE);
+ write_reg_64(port, REG_PLAY_CMD_NUM_WORDS_LO, (num_packets+1)*num_items*ITEM_SIZE/MEM_WORD_SIZE);
+ write_reg(port, REG_PLAY_CMD, PLAY_CMD_FINITE);
+ for (int i = 0; i < num_packets+1; i++) begin
+ blk_ctrl.recv_items(port, recv_items);
+ end
+ validate_play_position(port, mem_size-((num_packets-1)*num_items*ITEM_SIZE));
+
+ // Make sure there are no more packets
+ check_rx_idle(port);
+
+ test.end_test();
+ endtask : test_position
+
+
+ //---------------------------------------------------------------------------
// Test Filling the memory
//---------------------------------------------------------------------------
//
@@ -1795,6 +1926,7 @@ module rfnoc_block_replay_tb#(
test_4k_boundary();
test_small_packet();
test_timed_playback();
+ test_position();
test_full_memory();
//--------------------------------