fpga: rfnoc: Make Replay packet length independent of burst size
Before this change, the packet size output by the Replay block during playback was limited to length of a full memory burst transaction. This led to relatively small packets during playback (typically 2 KiB) and had other side effects, such as simultaneous playback from two different memory locations using different packet sizes because of differences in memory alignment. With this change, the configured packet size, as set by the register REG_PLAY_WORDS_PER_PKT, is used for all packets except the last packet of playback, which can of course be smaller. Original-commit: 082a733c326d6332d581d5b7bf9ee86a503ba502
This commit is contained in:
@@ -281,7 +281,7 @@ module axis_replay #(
|
|||||||
reg_play_cmd_time <= 0;
|
reg_play_cmd_time <= 0;
|
||||||
reg_play_words_per_pkt <= REG_PLAY_WORDS_PER_PKT_INIT;
|
reg_play_words_per_pkt <= REG_PLAY_WORDS_PER_PKT_INIT;
|
||||||
reg_item_size <= DEFAULT_ITEM_SIZE;
|
reg_item_size <= DEFAULT_ITEM_SIZE;
|
||||||
items_per_word <= 'bX;
|
items_per_word <= 'bX;
|
||||||
rec_restart <= 0;
|
rec_restart <= 0;
|
||||||
play_cmd_stop <= 0;
|
play_cmd_stop <= 0;
|
||||||
clear_cmd_fifo <= 0;
|
clear_cmd_fifo <= 0;
|
||||||
@@ -576,7 +576,7 @@ module axis_replay #(
|
|||||||
rec_restart_clear <= 1'b0;
|
rec_restart_clear <= 1'b0;
|
||||||
|
|
||||||
// Update wait timer
|
// Update wait timer
|
||||||
if (i_tvalid || !rec_fifo_occupied) begin
|
if ((i_tvalid && i_tready) || !rec_fifo_occupied) begin
|
||||||
// If a new word is presented to the input FIFO, or the FIFO is empty,
|
// If a new word is presented to the input FIFO, or the FIFO is empty,
|
||||||
// then reset the timer.
|
// then reset the timer.
|
||||||
rec_wait_timer <= 0;
|
rec_wait_timer <= 0;
|
||||||
@@ -943,78 +943,91 @@ module axis_replay #(
|
|||||||
//
|
//
|
||||||
// This section monitors the signals to/from the memory interface and
|
// This section monitors the signals to/from the memory interface and
|
||||||
// generates the TLAST and sideband signals. We assert TLAST at the end of
|
// generates the TLAST and sideband signals. We assert TLAST at the end of
|
||||||
// every read transaction and after every reg_play_words_per_pkt words, so
|
// every reg_play_words_per_pkt words and at the end of the last packet, so
|
||||||
// that no packets are longer than the length indicated by the
|
// that no packets are longer than the length indicated by the
|
||||||
// REG_PLAY_WORDS_PER_PKT register.
|
// REG_PLAY_WORDS_PER_PKT register.
|
||||||
//
|
//
|
||||||
// The sideband signals consist of the timestamp, has_time flag, and eob
|
// The sideband signals consist of the timestamp, has-time flag, and EOB (end
|
||||||
// flag. These are generated by the playback logic for each memory
|
// of burst) flag. Timestamp and has_time are set for the first packet of
|
||||||
// transaction.
|
// each playback. EOB applies to each packet but is only set to 1 for the
|
||||||
|
// last packet of a playback.
|
||||||
//
|
//
|
||||||
// The timing of this block relies on the fact that read_ctrl_ready is not
|
// The timing of this section relies on the fact axi_dma_master doesn't allow
|
||||||
// reasserted by the memory interface until after TLAST gets asserted.
|
// overlapping read transactions. This means that the next read_ctrl_ready
|
||||||
|
// won't be asserted until after previous memory transaction finishes being
|
||||||
|
// read out.
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
reg [MEM_COUNT_W-1:0] read_counter;
|
reg [MEM_COUNT_W-1:0] read_counter; // Track outstanding words to read
|
||||||
reg [ WPP_W-1:0] length_counter;
|
reg [ WPP_W-1:0] length_counter; // Track packet length
|
||||||
reg [ TIME_W-1:0] time_counter;
|
reg [ TIME_W-1:0] timestamp; // Timestamp for the current burst
|
||||||
reg play_fifo_i_tlast;
|
reg has_time; // Is current burst timed?
|
||||||
reg has_time;
|
reg eob; // End of burst
|
||||||
reg eob;
|
reg play_fifo_i_tlast; // End of packet
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
begin
|
begin
|
||||||
if (rst) begin
|
// synthesis translate_off
|
||||||
play_fifo_i_tlast <= 1'b0;
|
//
|
||||||
// Don't care:
|
// Check our assumption about non-overlapping read transactions.
|
||||||
read_counter <= {MEM_COUNT_W{1'bX}};
|
if (read_ctrl_ready && play_fifo_i_tvalid) begin
|
||||||
length_counter <= {MEM_COUNT_W+1{1'bX}};
|
$fatal(1, "New read transaction started before the previous one completed!");
|
||||||
time_counter <= {TIME_W{1'bX}};
|
end
|
||||||
has_time <= 1'bX;
|
// synthesis translate_on
|
||||||
eob <= 1'bX;
|
|
||||||
end else begin
|
if (read_ctrl_valid && read_ctrl_ready) begin
|
||||||
// Check if we're requesting a read transaction
|
read_counter <= read_count;
|
||||||
if (read_ctrl_valid && read_ctrl_ready) begin
|
|
||||||
// Initialize read_counter for new transaction
|
// If read_count is 0, then the next word is also the last word
|
||||||
read_counter <= read_count;
|
if (read_count == 0) begin
|
||||||
|
play_fifo_i_tlast <= 1'b1;
|
||||||
|
eob <= last_trans;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (play_fifo_i_tvalid && play_fifo_i_tready) begin
|
||||||
|
read_counter <= read_counter - 1;
|
||||||
|
length_counter <= length_counter - 1;
|
||||||
|
|
||||||
|
// Check if the current word is the last of the packet
|
||||||
|
if (play_fifo_i_tlast) begin
|
||||||
length_counter <= reg_play_words_per_pkt;
|
length_counter <= reg_play_words_per_pkt;
|
||||||
time_counter <= cmd_time;
|
|
||||||
has_time <= cmd_timed;
|
|
||||||
eob <= last_trans && (read_count < reg_play_words_per_pkt);
|
|
||||||
|
|
||||||
// If read_count is 0, then the first word is also the last word
|
// Clear tlast, unless the first word of the next packet is also the
|
||||||
if (read_count == 0) begin
|
// last word of the next packet.
|
||||||
play_fifo_i_tlast <= 1'b1;
|
if (!(last_trans && read_counter == 1)) begin
|
||||||
|
play_fifo_i_tlast <= 1'b0;
|
||||||
end
|
end
|
||||||
|
|
||||||
// Track the number of words read out by memory interface
|
// The timestamp only applies to the first packet, so disable for
|
||||||
end else if (read_data_valid && read_data_ready) begin
|
// subsequent packets.
|
||||||
read_counter <= read_counter - 1;
|
has_time <= 1'b0;
|
||||||
length_counter <= length_counter - 1;
|
|
||||||
time_counter <= time_counter + items_per_word;
|
|
||||||
|
|
||||||
// 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 memory
|
|
||||||
// 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 <= reg_play_words_per_pkt;
|
|
||||||
|
|
||||||
// Check if next packet is the end of the burst (EOB)
|
|
||||||
eob <= last_trans && (read_counter <= reg_play_words_per_pkt);
|
|
||||||
|
|
||||||
// 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
|
||||||
|
|
||||||
|
// Check if the next word will be the last of the packet.
|
||||||
|
//
|
||||||
|
// First, check if the next word is the last word of playback, in which
|
||||||
|
// case it's both the last word of the packet and the end of the burst.
|
||||||
|
if (last_trans && read_counter == 1) begin
|
||||||
|
play_fifo_i_tlast <= 1'b1;
|
||||||
|
eob <= 1;
|
||||||
|
|
||||||
|
// Next, check if this is the last word of the packet according to packet
|
||||||
|
// length. But note that the next word won't be the last if we're already
|
||||||
|
// outputting the last word of a burst on the current cycle.
|
||||||
|
end else if (length_counter == 2 && !(eob && play_fifo_i_tlast)) begin
|
||||||
|
play_fifo_i_tlast <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (play_state == PLAY_IDLE) begin
|
||||||
|
// Reset signals for the next playback
|
||||||
|
length_counter <= reg_play_words_per_pkt;
|
||||||
|
timestamp <= cmd_time_cf;
|
||||||
|
has_time <= cmd_timed_cf;
|
||||||
|
eob <= 0;
|
||||||
|
play_fifo_i_tlast <= 1'b0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1053,20 +1066,6 @@ module axis_replay #(
|
|||||||
.occupied ()
|
.occupied ()
|
||||||
);
|
);
|
||||||
|
|
||||||
reg play_fifo_i_sop = 1'b1;
|
|
||||||
|
|
||||||
// Make play_fifo_i_sop true whenever the next play_fifo_i word is the start
|
|
||||||
// of a packet.
|
|
||||||
always @(posedge clk) begin
|
|
||||||
if (rst) begin
|
|
||||||
play_fifo_i_sop <= 1'b1;
|
|
||||||
end else begin
|
|
||||||
if (play_fifo_i_tvalid & play_fifo_i_tready) begin
|
|
||||||
play_fifo_i_sop <= play_fifo_i_tlast;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Header Info FIFO
|
// Header Info FIFO
|
||||||
@@ -1080,6 +1079,7 @@ module axis_replay #(
|
|||||||
wire [(TIME_W+2)-1:0] hdr_fifo_i_tdata;
|
wire [(TIME_W+2)-1:0] hdr_fifo_i_tdata;
|
||||||
wire hdr_fifo_i_tvalid;
|
wire hdr_fifo_i_tvalid;
|
||||||
wire [(TIME_W+2)-1:0] hdr_fifo_o_tdata;
|
wire [(TIME_W+2)-1:0] hdr_fifo_o_tdata;
|
||||||
|
wire hdr_fifo_o_tvalid;
|
||||||
wire hdr_fifo_o_tready;
|
wire hdr_fifo_o_tready;
|
||||||
|
|
||||||
wire [15:0] hdr_fifo_space;
|
wire [15:0] hdr_fifo_space;
|
||||||
@@ -1097,20 +1097,31 @@ module axis_replay #(
|
|||||||
.i_tready (),
|
.i_tready (),
|
||||||
//
|
//
|
||||||
.o_tdata (hdr_fifo_o_tdata),
|
.o_tdata (hdr_fifo_o_tdata),
|
||||||
.o_tvalid (),
|
.o_tvalid (hdr_fifo_o_tvalid),
|
||||||
.o_tready (hdr_fifo_o_tready),
|
.o_tready (hdr_fifo_o_tready),
|
||||||
//
|
//
|
||||||
.space (hdr_fifo_space),
|
.space (hdr_fifo_space),
|
||||||
.occupied ()
|
.occupied ()
|
||||||
);
|
);
|
||||||
|
|
||||||
assign hdr_fifo_i_tdata = {has_time, eob, time_counter};
|
// synthesis translate_off
|
||||||
|
//
|
||||||
|
// The FIFO code above assumes the header info will always be available when
|
||||||
|
// the last word of the payload FIFO is read out. Check that assumption here.
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (hdr_fifo_o_tready && !hdr_fifo_o_tvalid) begin
|
||||||
|
$fatal(1, "Header FIFO read without valid data!");
|
||||||
|
end
|
||||||
|
end
|
||||||
|
// synthesis translate_on
|
||||||
|
|
||||||
|
assign hdr_fifo_i_tdata = {has_time, eob, timestamp };
|
||||||
|
|
||||||
// Pop the timestamp whenever we finish reading out a data packet
|
// Pop the timestamp whenever we finish reading out a data packet
|
||||||
assign hdr_fifo_o_tready = o_tvalid & o_tready & o_tlast;
|
assign hdr_fifo_o_tready = o_tvalid & o_tready & o_tlast;
|
||||||
|
|
||||||
// Write the timestamp at the start of each packet
|
// Write the timestamp at the start of each packet
|
||||||
assign hdr_fifo_i_tvalid = play_fifo_i_tvalid & play_fifo_i_tready & play_fifo_i_sop;
|
assign hdr_fifo_i_tvalid = play_fifo_i_tvalid & play_fifo_i_tready & play_fifo_i_tlast;
|
||||||
|
|
||||||
assign { o_thas_time, o_teob, o_ttimestamp } = hdr_fifo_o_tdata;
|
assign { o_thas_time, o_teob, o_ttimestamp } = hdr_fifo_o_tdata;
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ module rfnoc_block_replay_tb#(
|
|||||||
|
|
||||||
`include "rfnoc_block_replay_regs.vh"
|
`include "rfnoc_block_replay_regs.vh"
|
||||||
|
|
||||||
|
`define MIN(X,Y) ((X)<(Y)?(X):(Y))
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Testbench Configuration
|
// Testbench Configuration
|
||||||
@@ -535,6 +537,8 @@ module rfnoc_block_replay_tb#(
|
|||||||
"Buffer size extends beyond available memory");
|
"Buffer size extends beyond available memory");
|
||||||
`ASSERT_FATAL(spp * ITEM_SIZE % MEM_WORD_SIZE == 0,
|
`ASSERT_FATAL(spp * ITEM_SIZE % MEM_WORD_SIZE == 0,
|
||||||
"Requested SPP must be a multiple of the memory word size");
|
"Requested SPP must be a multiple of the memory word size");
|
||||||
|
`ASSERT_FATAL(spp <= 2**MTU,
|
||||||
|
"Requested SPP exceeds MTU");
|
||||||
|
|
||||||
// Update record buffer settings
|
// Update record buffer settings
|
||||||
write_reg_64(port, REG_REC_BASE_ADDR_LO, base_addr);
|
write_reg_64(port, REG_REC_BASE_ADDR_LO, base_addr);
|
||||||
@@ -583,6 +587,7 @@ module rfnoc_block_replay_tb#(
|
|||||||
// exp_items : Queue of the items you expect to receive
|
// exp_items : Queue of the items you expect to receive
|
||||||
// eob : Indicates if we expect EOB to be set for the last item (set
|
// eob : Indicates if we expect EOB to be set for the last item (set
|
||||||
// to 1'bX to skip this check)
|
// to 1'bX to skip this check)
|
||||||
|
// spp : Samples per packet to expect. Set to 0 to skip this check.
|
||||||
// timestamp : The timestamp we expect to receive for the first item (set to
|
// timestamp : The timestamp we expect to receive for the first item (set to
|
||||||
// 'X to skip timestamp checking)
|
// 'X to skip timestamp checking)
|
||||||
//
|
//
|
||||||
@@ -591,6 +596,7 @@ module rfnoc_block_replay_tb#(
|
|||||||
output string error_msg,
|
output string error_msg,
|
||||||
input item_t exp_items[$],
|
input item_t exp_items[$],
|
||||||
input logic eob = 1'b1,
|
input logic eob = 1'b1,
|
||||||
|
input int spp = SPP,
|
||||||
input logic [63:0] timestamp = 64'bX
|
input logic [63:0] timestamp = 64'bX
|
||||||
);
|
);
|
||||||
item_t recv_items[$];
|
item_t recv_items[$];
|
||||||
@@ -614,9 +620,9 @@ module rfnoc_block_replay_tb#(
|
|||||||
// Check the packet length
|
// Check the packet length
|
||||||
if (item_count + recv_items.size() > exp_items.size()) begin
|
if (item_count + recv_items.size() > exp_items.size()) begin
|
||||||
$sformat(error_msg,
|
$sformat(error_msg,
|
||||||
"On packet %0d, size exceeds expected by %0d items",
|
"On packet %0d, size is %0d items, which exceeds expected by %0d items.",
|
||||||
packet_count,
|
packet_count, recv_items.size(),
|
||||||
(item_count + recv_items.size()) - exp_items.size());
|
(item_count + recv_items.size()) - exp_items.size());
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -645,8 +651,27 @@ module rfnoc_block_replay_tb#(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
// Check the timestamp
|
// Check the payload length against expected SPP
|
||||||
if (timestamp !== 64'bX) begin
|
if (spp > 0) begin
|
||||||
|
// If this is NOT the last packet, then its length should match the SPP.
|
||||||
|
// If it is the last packet, then it can be shorter than SPP.
|
||||||
|
if (!pkt_info.eob) begin
|
||||||
|
if (recv_items.size() != spp) begin
|
||||||
|
$sformat(error_msg,
|
||||||
|
"On packet %0d, expected SPP of %0d but packet has %0d items",
|
||||||
|
packet_count, spp, recv_items.size());
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
if (recv_items.size() > spp) begin
|
||||||
|
$sformat(error_msg,
|
||||||
|
"On packet %0d (EOB), expected SPP of %0d or less but packet has %0d items",
|
||||||
|
packet_count, spp, recv_items.size());
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
// Check the timestamp (only first packet should have a timestamp)
|
||||||
|
if (timestamp !== 64'bX && packet_count == 0) begin
|
||||||
if (!pkt_info.timestamp) begin
|
if (!pkt_info.timestamp) begin
|
||||||
$sformat(error_msg,
|
$sformat(error_msg,
|
||||||
"On packet %0d, timestamp is missing",
|
"On packet %0d, timestamp is missing",
|
||||||
@@ -925,37 +950,40 @@ module rfnoc_block_replay_tb#(
|
|||||||
// For each test below, we record two memory bursts and playback two memory
|
// For each test below, we record two memory bursts and playback two memory
|
||||||
// bursts. Each time we change the playback packet size to test boundary
|
// bursts. Each time we change the playback packet size to test boundary
|
||||||
// conditions.
|
// conditions.
|
||||||
|
//
|
||||||
|
// Note that we can't let the SPP exceed the MTU, so if the burst size is
|
||||||
|
// too large, we won't be testing the full size.
|
||||||
|
|
||||||
// Test packet size equals burst size
|
// Test packet size equals burst size
|
||||||
spp = MEM_BURST_LEN * MEM_WORD_SIZE / ITEM_SIZE;
|
spp = `MIN(MEM_BURST_LEN * MEM_WORD_SIZE / ITEM_SIZE, 2**MTU);
|
||||||
start_replay(port, send_items, buffer_size, num_items, spp);
|
start_replay(port, send_items, buffer_size, num_items, spp);
|
||||||
verify_rx_data(port, error_string, send_items, 1);
|
verify_rx_data(port, error_string, send_items, 1, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// Test packet is one less than burst size
|
// Test packet is one less than burst size
|
||||||
spp = (MEM_BURST_LEN-1) * MEM_WORD_SIZE / ITEM_SIZE;
|
spp = `MIN((MEM_BURST_LEN-1) * MEM_WORD_SIZE / ITEM_SIZE, 2**MTU-(MEM_WORD_SIZE / ITEM_SIZE));
|
||||||
start_replay(port, send_items, buffer_size, num_items, spp);
|
start_replay(port, send_items, buffer_size, num_items, spp);
|
||||||
verify_rx_data(port, error_string, send_items, 1);
|
verify_rx_data(port, error_string, send_items, 1, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// Test packet is one more than burst size
|
// Test packet is one more than burst size
|
||||||
spp = (MEM_BURST_LEN+1) * MEM_WORD_SIZE / ITEM_SIZE;
|
spp = `MIN((MEM_BURST_LEN+1) * MEM_WORD_SIZE / ITEM_SIZE, 2**MTU);
|
||||||
start_replay(port, send_items, buffer_size, num_items, spp);
|
start_replay(port, send_items, buffer_size, num_items, spp);
|
||||||
verify_rx_data(port, error_string, send_items, 1);
|
verify_rx_data(port, error_string, send_items, 1, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// For each test below, we record two memory bursts and playback one memory
|
// For each test below, we record two memory bursts and playback one memory
|
||||||
// burst plus or minus one word, keeping the packet size the same.
|
// burst plus or minus one word, keeping the packet size the same.
|
||||||
spp = MEM_BURST_LEN * MEM_WORD_SIZE / ITEM_SIZE;
|
spp = `MIN(MEM_BURST_LEN * MEM_WORD_SIZE / ITEM_SIZE, 2**MTU);
|
||||||
|
|
||||||
// Playback one less than burst/packet size
|
// Playback one less than burst/packet size
|
||||||
start_replay(port, send_items, buffer_size, spp-MEM_WORD_SIZE/ITEM_SIZE, spp);
|
start_replay(port, send_items, buffer_size, spp-MEM_WORD_SIZE/ITEM_SIZE, spp);
|
||||||
verify_rx_data(port, error_string, send_items[0:spp-1-MEM_WORD_SIZE/ITEM_SIZE], 1);
|
verify_rx_data(port, error_string, send_items[0:spp-1-MEM_WORD_SIZE/ITEM_SIZE], 1, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// Playback one more than burst/packet size
|
// Playback one more than burst/packet size
|
||||||
start_replay(port, send_items, buffer_size, spp+MEM_WORD_SIZE/ITEM_SIZE, spp);
|
start_replay(port, send_items, buffer_size, spp+MEM_WORD_SIZE/ITEM_SIZE, spp);
|
||||||
verify_rx_data(port, error_string, send_items[0:spp-1+MEM_WORD_SIZE/ITEM_SIZE], 1);
|
verify_rx_data(port, error_string, send_items[0:spp-1+MEM_WORD_SIZE/ITEM_SIZE], 1, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// Make sure there are no more packets
|
// Make sure there are no more packets
|
||||||
@@ -1016,8 +1044,8 @@ module rfnoc_block_replay_tb#(
|
|||||||
|
|
||||||
// Set number of words to test
|
// Set number of words to test
|
||||||
buffer_size = (3 * MEM_BURST_LEN) / 2 * MEM_WORD_SIZE; // 1.5 memory bursts in size (in bytes)
|
buffer_size = (3 * MEM_BURST_LEN) / 2 * MEM_WORD_SIZE; // 1.5 memory bursts in size (in bytes)
|
||||||
num_items_rec = buffer_size / ITEM_SIZE; // 1.5 memory bursts in size (in CHDR words)
|
num_items_rec = buffer_size / ITEM_SIZE; // 1.5 memory bursts in size (in samples)
|
||||||
num_items_play = 2 * MEM_BURST_LEN * MEM_WORD_SIZE / // 2 memory bursts in size (in CHDR words)
|
num_items_play = 2 * MEM_BURST_LEN * MEM_WORD_SIZE / // 2 memory bursts in size (in samples)
|
||||||
ITEM_SIZE;
|
ITEM_SIZE;
|
||||||
|
|
||||||
// Start playback of data
|
// Start playback of data
|
||||||
@@ -1045,19 +1073,25 @@ module rfnoc_block_replay_tb#(
|
|||||||
item_t send_items[$];
|
item_t send_items[$];
|
||||||
string error_string;
|
string error_string;
|
||||||
logic [31:0] cmd;
|
logic [31:0] cmd;
|
||||||
int num_items, mem_words;
|
int num_items, mem_words, spp;
|
||||||
|
|
||||||
test.start_test("Test continuous mode", TEST_TIMEOUT);
|
test.start_test("Test continuous mode", TEST_TIMEOUT);
|
||||||
|
|
||||||
mem_words = 70;
|
mem_words = 70;
|
||||||
num_items = mem_words * MEM_WORD_SIZE / ITEM_SIZE;
|
num_items = mem_words * MEM_WORD_SIZE / ITEM_SIZE;
|
||||||
|
|
||||||
|
// Make sure the spp evenly divides our test size, or else we'll end a
|
||||||
|
// check mid packet, which verify_rx_data doesn't support.
|
||||||
|
spp = num_items / 2;
|
||||||
|
`ASSERT_ERROR(num_items % spp == 0,
|
||||||
|
"num_items should be a multiple of spp for this test");
|
||||||
|
|
||||||
// Update record buffer settings
|
// Update record buffer settings
|
||||||
write_reg_64(port, REG_REC_BASE_ADDR_LO, 0);
|
write_reg_64(port, REG_REC_BASE_ADDR_LO, 0);
|
||||||
write_reg_64(port, REG_REC_BUFFER_SIZE_LO, num_items*ITEM_SIZE);
|
write_reg_64(port, REG_REC_BUFFER_SIZE_LO, num_items*ITEM_SIZE);
|
||||||
write_reg_64(port, REG_PLAY_BASE_ADDR_LO, 0);
|
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_BUFFER_SIZE_LO, num_items*ITEM_SIZE);
|
||||||
write_reg (port, REG_PLAY_WORDS_PER_PKT, SPP * ITEM_SIZE/MEM_WORD_SIZE);
|
write_reg (port, REG_PLAY_WORDS_PER_PKT, spp * ITEM_SIZE/MEM_WORD_SIZE);
|
||||||
|
|
||||||
// Restart the record buffer
|
// Restart the record buffer
|
||||||
write_reg(port, REG_REC_RESTART, 0);
|
write_reg(port, REG_REC_RESTART, 0);
|
||||||
@@ -1071,16 +1105,15 @@ module rfnoc_block_replay_tb#(
|
|||||||
|
|
||||||
// Make sure the REG_PLAY_CMD_NUM_WORDS value is ignored by setting it to
|
// Make sure the REG_PLAY_CMD_NUM_WORDS value is ignored by setting it to
|
||||||
// something smaller than what we receive.
|
// something smaller than what we receive.
|
||||||
write_reg_64(port, REG_PLAY_CMD_NUM_WORDS_LO, mem_words);
|
write_reg_64(port, REG_PLAY_CMD_NUM_WORDS_LO, 0);
|
||||||
|
|
||||||
// Send command for continuous playback
|
// Send command for continuous playback
|
||||||
cmd = PLAY_CMD_CONTINUOUS;
|
cmd = PLAY_CMD_CONTINUOUS;
|
||||||
write_reg_64(port, REG_PLAY_CMD_NUM_WORDS_LO, mem_words);
|
|
||||||
write_reg(port, REG_PLAY_CMD, cmd);
|
write_reg(port, REG_PLAY_CMD, cmd);
|
||||||
|
|
||||||
// Check the output, looking for the full set of data, multiple times
|
// Check the output, looking for the full set of data, multiple times
|
||||||
repeat (5) begin
|
repeat (5) begin
|
||||||
verify_rx_data(port, error_string, send_items, 0);
|
verify_rx_data(port, error_string, send_items, 0, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1153,6 +1186,7 @@ module rfnoc_block_replay_tb#(
|
|||||||
|
|
||||||
// Check the result
|
// Check the result
|
||||||
verify_rx_data(port, error_string, send_items, 1);
|
verify_rx_data(port, error_string, send_items, 1);
|
||||||
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// Check the fullness
|
// Check the fullness
|
||||||
read_reg_64(port, REG_REC_FULLNESS_LO, val64);
|
read_reg_64(port, REG_REC_FULLNESS_LO, val64);
|
||||||
@@ -1264,15 +1298,21 @@ module rfnoc_block_replay_tb#(
|
|||||||
item_t send_items[$];
|
item_t send_items[$];
|
||||||
item_t exp_items[$];
|
item_t exp_items[$];
|
||||||
string error_string;
|
string error_string;
|
||||||
int num_items, mem_words;
|
int num_items, spp;
|
||||||
int num_items_buf;
|
int num_items_buf;
|
||||||
logic [63:0] val64;
|
logic [63:0] val64;
|
||||||
|
|
||||||
test.start_test("Test overfilled record buffer", TEST_TIMEOUT);
|
test.start_test("Test overfilled record buffer", TEST_TIMEOUT);
|
||||||
|
|
||||||
// Choose the sizes we want to use for this test
|
// Choose the sizes we want to use for this test
|
||||||
num_items = 97*MEM_WORD_SIZE/ITEM_SIZE; // Number of items to record
|
num_items = 98*MEM_WORD_SIZE/ITEM_SIZE; // Number of items to record
|
||||||
num_items_buf = 43*MEM_WORD_SIZE/ITEM_SIZE; // Size of buffer to use in items
|
num_items_buf = 44*MEM_WORD_SIZE/ITEM_SIZE; // Size of buffer to use in items
|
||||||
|
|
||||||
|
// Make sure the spp evenly divides our test size, or else we'll end a
|
||||||
|
// check mid packet, which verify_rx_data doesn't support.
|
||||||
|
spp = num_items_buf / 4;
|
||||||
|
`ASSERT_ERROR(num_items_buf % spp == 0,
|
||||||
|
"num_items_buf should be a multiple of spp for this test");
|
||||||
|
|
||||||
// Restart the record buffer
|
// Restart the record buffer
|
||||||
write_reg(port, REG_REC_RESTART, 0);
|
write_reg(port, REG_REC_RESTART, 0);
|
||||||
@@ -1281,17 +1321,17 @@ module rfnoc_block_replay_tb#(
|
|||||||
send_items = gen_test_data(num_items);
|
send_items = gen_test_data(num_items);
|
||||||
|
|
||||||
// Start playback of the larger size
|
// Start playback of the larger size
|
||||||
start_replay(port, send_items, num_items_buf*ITEM_SIZE, num_items);
|
start_replay(port, send_items, num_items_buf*ITEM_SIZE, num_items, spp);
|
||||||
|
|
||||||
// We should get two frames of num_items_buf, then one smaller frame to
|
// We should get two frames of num_items_buf, then one smaller frame to
|
||||||
// bring us up to num_items total.
|
// bring us up to num_items total.
|
||||||
exp_items = send_items[0 : num_items_buf-1];
|
exp_items = send_items[0 : num_items_buf-1];
|
||||||
for (int i = 0; i < 2; i ++) begin
|
for (int i = 0; i < 2; i ++) begin
|
||||||
verify_rx_data(port, error_string, exp_items, 0);
|
verify_rx_data(port, error_string, exp_items, 0, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
end
|
end
|
||||||
exp_items = exp_items[0 : (num_items % num_items_buf)-1];
|
exp_items = exp_items[0 : (num_items % num_items_buf)-1];
|
||||||
verify_rx_data(port, error_string, exp_items, 1);
|
verify_rx_data(port, error_string, exp_items, 1, spp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
// Make sure REG_REC_FULLNESS didn't keep increasing
|
// Make sure REG_REC_FULLNESS didn't keep increasing
|
||||||
@@ -1447,12 +1487,11 @@ module rfnoc_block_replay_tb#(
|
|||||||
send_items = gen_test_data(num_items);
|
send_items = gen_test_data(num_items);
|
||||||
start_replay(port, send_items, buffer_size, num_items, pkt_size_items);
|
start_replay(port, send_items, buffer_size, num_items, pkt_size_items);
|
||||||
|
|
||||||
// We should get 8 small packets instead of 2 large ones, with EOB set on
|
// We should get 8 small packets with EOB set on the last packet.
|
||||||
// the last packet.
|
|
||||||
for (int k = 0; k < 8; k ++) begin
|
for (int k = 0; k < 8; k ++) begin
|
||||||
verify_rx_data(port, error_string,
|
verify_rx_data(port, error_string,
|
||||||
send_items[pkt_size_items*k : pkt_size_items*(k+1)-1],
|
send_items[pkt_size_items*k : pkt_size_items*(k+1)-1],
|
||||||
(k == 7 ? 1 : 0));
|
(k == 7 ? 1 : 0), pkt_size_items);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1473,7 +1512,7 @@ module rfnoc_block_replay_tb#(
|
|||||||
// with EOB set on the last packet.
|
// with EOB set on the last packet.
|
||||||
for (int i=0; i < num_items; i += pkt_size_items) begin
|
for (int i=0; i < num_items; i += pkt_size_items) begin
|
||||||
verify_rx_data(port, error_string, send_items[i:i+pkt_size_items-1],
|
verify_rx_data(port, error_string, send_items[i:i+pkt_size_items-1],
|
||||||
i == num_items-pkt_size_items ? 1 : 0);
|
i == num_items-pkt_size_items ? 1 : 0, pkt_size_items);
|
||||||
`ASSERT_FATAL(error_string == "", error_string);
|
`ASSERT_FATAL(error_string == "", error_string);
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1507,7 +1546,7 @@ module rfnoc_block_replay_tb#(
|
|||||||
send_items = gen_test_data(num_items);
|
send_items = gen_test_data(num_items);
|
||||||
start_replay(port, send_items, buffer_size, num_items, spp, 0, 0, timestamp);
|
start_replay(port, send_items, buffer_size, num_items, spp, 0, 0, timestamp);
|
||||||
|
|
||||||
verify_rx_data(port, error_string, send_items, 1, timestamp);
|
verify_rx_data(port, error_string, send_items, 1, spp, timestamp);
|
||||||
`ASSERT_ERROR(error_string == "", error_string);
|
`ASSERT_ERROR(error_string == "", error_string);
|
||||||
|
|
||||||
test.end_test();
|
test.end_test();
|
||||||
@@ -1581,6 +1620,8 @@ module rfnoc_block_replay_tb#(
|
|||||||
blk_ctrl.send_items(port+1, port1_data);
|
blk_ctrl.send_items(port+1, port1_data);
|
||||||
|
|
||||||
// Play back on each port
|
// Play back on each port
|
||||||
|
write_reg(port+0, REG_PLAY_WORDS_PER_PKT, SPP*ITEM_SIZE/MEM_WORD_SIZE);
|
||||||
|
write_reg(port+1, REG_PLAY_WORDS_PER_PKT, SPP*ITEM_SIZE/MEM_WORD_SIZE);
|
||||||
write_reg_64(port+0, REG_PLAY_CMD_NUM_WORDS_LO, mem_words);
|
write_reg_64(port+0, REG_PLAY_CMD_NUM_WORDS_LO, mem_words);
|
||||||
write_reg_64(port+1, REG_PLAY_CMD_NUM_WORDS_LO, mem_words);
|
write_reg_64(port+1, REG_PLAY_CMD_NUM_WORDS_LO, mem_words);
|
||||||
write_reg(port+0, REG_PLAY_CMD, PLAY_CMD_FINITE);
|
write_reg(port+0, REG_PLAY_CMD, PLAY_CMD_FINITE);
|
||||||
@@ -1704,7 +1745,7 @@ module rfnoc_block_replay_tb#(
|
|||||||
// Generate a string for the name of this instance of the testbench
|
// Generate a string for the name of this instance of the testbench
|
||||||
tb_name = $sformatf( {
|
tb_name = $sformatf( {
|
||||||
"rfnoc_block_replay_tb\n",
|
"rfnoc_block_replay_tb\n",
|
||||||
"CHDR_W = %03d, ITEM_W = %02d, NUM_PORTS = %d,\n",
|
"CHDR_W = %03d, ITEM_W = %02d, NUM_PORTS = %0d,\n",
|
||||||
"MEM_DATA_W = %03d, MEM_ADDR_W = %02d,\n",
|
"MEM_DATA_W = %03d, MEM_ADDR_W = %02d,\n",
|
||||||
"TEST_REGS = %03d, TEST_FULL = %02d,\n",
|
"TEST_REGS = %03d, TEST_FULL = %02d,\n",
|
||||||
"STALL_PROB = %03d" },
|
"STALL_PROB = %03d" },
|
||||||
|
|||||||
Reference in New Issue
Block a user