242 lines
7.0 KiB
Systemverilog
242 lines
7.0 KiB
Systemverilog
`timescale 1ns / 1ps
|
|
|
|
module sampler_tb #(
|
|
// Параметры тестбенча
|
|
parameter int DATA_WIDTH = 12, // bitwidth of sampled data. Equal to ADC bitwidth
|
|
parameter int PACK_FACTOR = 1, // packing of several numbers in one axi-stream tdata transaction
|
|
parameter bit PROCESS_MODE = 0, // signed (1) / unsigned (0)
|
|
parameter real CLK_PERIOD = 15.3846,
|
|
parameter int OTR_OFFSET = 0 // Out of Range offset number clipping
|
|
);
|
|
// Вычислимые константы
|
|
// Диапазон значений семплера
|
|
localparam int MIN_VALUE = PROCESS_MODE ? -2**(DATA_WIDTH-1) : 0;
|
|
localparam int MAX_VALUE = PROCESS_MODE ? 2**(DATA_WIDTH-1)-1 : (2**DATA_WIDTH)-1;
|
|
|
|
logic clk;
|
|
logic rst_dut;
|
|
logic rst_gen;
|
|
|
|
wire [DATA_WIDTH-1:0] data_in;
|
|
wire out_of_range;
|
|
|
|
logic [31:0] smp_num;
|
|
|
|
logic done;
|
|
logic request;
|
|
|
|
logic [DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata;
|
|
logic m_axis_tvalid;
|
|
|
|
sampler #(
|
|
.DATA_WIDTH (DATA_WIDTH),
|
|
.PACK_FACTOR (PACK_FACTOR),
|
|
.PROCESS_MODE(PROCESS_MODE)
|
|
) dut (
|
|
.clk_in (clk),
|
|
.rst (rst_dut),
|
|
|
|
.data_in (data_in),
|
|
.out_of_range (out_of_range),
|
|
|
|
.smp_num (smp_num),
|
|
.done (done),
|
|
|
|
.m_axis_tdata (m_axis_tdata),
|
|
.m_axis_tvalid(m_axis_tvalid),
|
|
|
|
.request (request)
|
|
);
|
|
|
|
// =====================================================
|
|
// CLOCK
|
|
// =====================================================
|
|
initial begin
|
|
clk = 0;
|
|
forever #(CLK_PERIOD/2) clk = ~clk;
|
|
end
|
|
|
|
// =====================================================
|
|
// RESET
|
|
// =====================================================
|
|
task automatic reset_dut();
|
|
@(posedge clk);
|
|
rst_dut = 1;
|
|
@(posedge clk);
|
|
rst_dut = 0;
|
|
endtask
|
|
|
|
// =====================================================
|
|
// FEED DATA
|
|
// =====================================================
|
|
triangle_wave_gen #(
|
|
.DATA_WIDTH(DATA_WIDTH),
|
|
.OFFSET(OTR_OFFSET), // offset of bits from '0 and '1 for OTR
|
|
.STEP(1) // LSB bit per clock
|
|
) signal_gen (
|
|
.clk(clk),
|
|
.rst(rst_gen),
|
|
.signal(data_in),
|
|
.otr(out_of_range)
|
|
);
|
|
|
|
// =====================================================
|
|
// TEST TASKS
|
|
// =====================================================
|
|
task automatic run_test_case(
|
|
input int sample_num
|
|
);
|
|
logic [DATA_WIDTH-1:0] input_values[$];
|
|
logic [DATA_WIDTH-1:0] output_values[$];
|
|
bit flag;
|
|
int tmp_input_val, tmp_output_val;
|
|
|
|
// Startup sequence
|
|
rst_gen <= 1;
|
|
smp_num <= sample_num;
|
|
request <= 1;
|
|
@(posedge clk);
|
|
|
|
// syncronize
|
|
while (!done)
|
|
@(posedge clk);
|
|
request <= 0;
|
|
|
|
// Wait for sync and start signal generator
|
|
// while (!dut.synced)
|
|
// @(posedge clk);
|
|
wait(dut.synced === 1);
|
|
rst_gen <= 0;
|
|
|
|
// Wait for valid data
|
|
fork
|
|
begin : stat_mon_proc
|
|
forever begin
|
|
@(posedge clk);
|
|
input_values.push_back(data_in);
|
|
if (m_axis_tvalid) begin
|
|
for (int i = 0; i < PACK_FACTOR; i++)
|
|
output_values.push_back(m_axis_tdata[DATA_WIDTH*i +: DATA_WIDTH]);
|
|
end
|
|
end
|
|
end
|
|
join_none
|
|
|
|
// Wait until end
|
|
// while (dut.synced)
|
|
// @(posedge clk);
|
|
wait(dut.synced === 0);
|
|
|
|
disable stat_mon_proc;
|
|
// Pop last input value. Signal is ahead of tdata for 1 cycle
|
|
input_values.pop_back();
|
|
|
|
// check data length correct
|
|
if ((input_values.size() - (input_values.size() % PACK_FACTOR)) != output_values.size()) begin
|
|
$display("[ERROR] -run_test_case- Input queue size don't equal to output queue size: %0d vs %0d", input_values.size(), output_values.size());
|
|
$finish;
|
|
end
|
|
flag = 0;
|
|
for (int i = 0; i < output_values.size(); i++) begin
|
|
// clip value for OTR
|
|
tmp_input_val = int'(input_values[i]) + MIN_VALUE;
|
|
tmp_output_val = PROCESS_MODE ?
|
|
int'($signed({output_values[i][DATA_WIDTH-1], output_values[i]})) :
|
|
int'(output_values[i]);
|
|
|
|
if ((tmp_input_val < MIN_VALUE + OTR_OFFSET) ||
|
|
(tmp_input_val > MAX_VALUE - OTR_OFFSET)) begin
|
|
// need clipping
|
|
tmp_input_val = ((tmp_input_val - MIN_VALUE) < 2**(DATA_WIDTH-1)) ?
|
|
MIN_VALUE : MAX_VALUE;
|
|
end
|
|
|
|
if (tmp_input_val != tmp_output_val)
|
|
flag = 1;
|
|
end
|
|
// $display("Total: %0d", output_values.size());
|
|
if (flag) begin
|
|
$display("[ERROR] -run_test_case- Sampled data not correct and not equal to generated signal.");
|
|
$finish;
|
|
end
|
|
endtask
|
|
|
|
// =====================================================
|
|
// MAIN
|
|
// =====================================================
|
|
initial begin
|
|
int random_number;
|
|
|
|
$display("\n=== BASIC TEST ===");
|
|
|
|
rst_dut = 1;
|
|
rst_gen = 1;
|
|
smp_num = 0;
|
|
repeat(2) @(posedge clk);
|
|
rst_dut = 0;
|
|
repeat(2) @(posedge clk);
|
|
|
|
$display("basic test #1");
|
|
run_test_case(10);
|
|
run_test_case(100);
|
|
run_test_case(10000);
|
|
$display("basic test #2");
|
|
run_test_case(0);
|
|
|
|
$display("\n=== RANDOM STRESS TEST ===");
|
|
for (int i = 0; i < 10; i++) begin
|
|
$display("Random test #%0d", i);
|
|
random_number = $urandom_range(0, 3 * 2**(DATA_WIDTH)); // up to 1.5 triangle waves
|
|
run_test_case(random_number);
|
|
end
|
|
|
|
$display("\n=== TEST FINISHED ===");
|
|
$finish;
|
|
|
|
end
|
|
|
|
endmodule
|
|
|
|
module triangle_wave_gen #(
|
|
parameter DATA_WIDTH = 12,
|
|
parameter OFFSET = 100, // offset of bits from '0 and '1 for OTR
|
|
parameter STEP = 1 // LSB bit per clock
|
|
) (
|
|
input clk,
|
|
input rst,
|
|
output logic [DATA_WIDTH-1:0] signal,
|
|
output logic otr
|
|
);
|
|
logic [DATA_WIDTH:0] counter;
|
|
logic direction;
|
|
|
|
initial begin
|
|
counter = '0;
|
|
direction = 1;
|
|
end
|
|
|
|
assign signal = counter > (2**DATA_WIDTH-1) ? (2**DATA_WIDTH-1) : counter;
|
|
|
|
always_comb begin
|
|
if (signal < OFFSET || (2**DATA_WIDTH - signal) <= OFFSET)
|
|
otr <= 1;
|
|
else
|
|
otr <= 0;
|
|
end
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
counter = 0;
|
|
direction = 1;
|
|
end else begin
|
|
if (direction)
|
|
counter += STEP;
|
|
else
|
|
counter -= STEP;
|
|
|
|
if (counter >= 2**DATA_WIDTH-1 || counter <= 0)
|
|
direction <= ~direction;
|
|
end
|
|
end
|
|
endmodule
|