diff options
| author | Wade Fife <wade.fife@ettus.com> | 2020-07-31 16:09:07 -0500 | 
|---|---|---|
| committer | Wade Fife <wade.fife@ettus.com> | 2020-08-10 09:58:02 -0500 | 
| commit | 9157e11795f3ca86dae2ee930e60a79470d1447f (patch) | |
| tree | 533b768ca23bbcc0a60fa2e6361e1e386c5f68ad /fpga/usrp3/lib/rfnoc | |
| parent | 7b3bf4bdc00f9c6f56edc1823fade0408aec290f (diff) | |
| download | uhd-9157e11795f3ca86dae2ee930e60a79470d1447f.tar.gz uhd-9157e11795f3ca86dae2ee930e60a79470d1447f.tar.bz2 uhd-9157e11795f3ca86dae2ee930e60a79470d1447f.zip | |
fpga: rfnoc: Add tests to FFT block
This adds additional tests to the testbench to cover register reads and
basic IFFT functionaltiy.
Diffstat (limited to 'fpga/usrp3/lib/rfnoc')
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft.v | 22 | ||||
| -rw-r--r-- | fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv | 219 | 
2 files changed, 202 insertions, 39 deletions
| diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft.v b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft.v index 929774766..7096b26d0 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft.v +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft.v @@ -226,6 +226,13 @@ module rfnoc_block_fft #(    localparam [31:0] SR_FFT_SCALING      = 135;    localparam [31:0] SR_FFT_SHIFT_CONFIG = 136; +  localparam RB_FFT_RESET        = 0; +  localparam RB_MAGNITUDE_OUT    = 1; +  localparam RB_FFT_SIZE_LOG2    = 2; +  localparam RB_FFT_DIRECTION    = 3; +  localparam RB_FFT_SCALING      = 4; +  localparam RB_FFT_SHIFT_CONFIG = 5; +    // FFT Output    localparam [1:0] COMPLEX_OUT = 0;    localparam [1:0] MAG_OUT     = 1; @@ -284,8 +291,7 @@ module rfnoc_block_fft #(      .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),      .o_tdata(fft_core_size_log2_tdata), .o_tlast(), .o_tvalid(fft_core_size_log2_tvalid), .o_tready(fft_core_size_log2_tready)); -  // Forward = 0, Reverse = 1 -  localparam DEFAULT_FFT_DIRECTION = 0; +  localparam DEFAULT_FFT_DIRECTION = FFT_FORWARD;    wire fft_direction_tdata;    wire fft_direction_tvalid, fft_direction_tready;    axi_setting_reg #( @@ -504,12 +510,12 @@ module rfnoc_block_fft #(    // Readback registers    always @*      case(rb_addr) -      3'd0    : rb_data <= {63'd0, fft_reset}; -      3'd1    : rb_data <= {62'd0, magnitude_out}; -      3'd2    : rb_data <= {fft_size_log2_tdata}; -      3'd3    : rb_data <= {63'd0, fft_direction_tdata}; -      3'd4    : rb_data <= {52'd0, fft_scaling_tdata}; -      3'd5    : rb_data <= {62'd0, fft_shift_config_tdata}; +      RB_FFT_RESET        : rb_data <= {63'd0, fft_reset}; +      RB_MAGNITUDE_OUT    : rb_data <= {62'd0, magnitude_out}; +      RB_FFT_SIZE_LOG2    : rb_data <= {fft_size_log2_tdata}; +      RB_FFT_DIRECTION    : rb_data <= {63'd0, fft_direction_tdata}; +      RB_FFT_SCALING      : rb_data <= {52'd0, fft_scaling_tdata}; +      RB_FFT_SHIFT_CONFIG : rb_data <= {62'd0, fft_shift_config_tdata};        default : rb_data <= 64'h0BADC0DE0BADC0DE;    endcase diff --git a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv index 0f442ddd4..b243ff24f 100644 --- a/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv +++ b/fpga/usrp3/lib/rfnoc/blocks/rfnoc_block_fft/rfnoc_block_fft_tb.sv @@ -30,7 +30,7 @@ module rfnoc_block_fft_tb();    // Block configuration    localparam int NOC_ID        = 32'hFF70_0000;    localparam int CHDR_W        = 64; -  localparam int SAMP_W        = 32; +  localparam int ITEM_W        = 32;    localparam int THIS_PORTID   = 'h123;    localparam int MTU           = 10;    localparam int NUM_PORTS     = 1; @@ -41,7 +41,6 @@ module rfnoc_block_fft_tb();    // FFT settings    localparam [31:0] FFT_SIZE         = 256;    localparam [31:0] FFT_SIZE_LOG2    = $clog2(FFT_SIZE); -  const logic [31:0] FFT_DIRECTION    = DUT.FFT_FORWARD;  // Forward    localparam [31:0] FFT_SCALING      = 12'b011010101010;           // Conservative scaling of 1/N    localparam [31:0] FFT_SHIFT_CONFIG = 0;                          // Normal FFT shift    localparam FFT_BIN                 = FFT_SIZE/8 + FFT_SIZE/2;    // 1/8 sample rate freq + FFT shift @@ -61,7 +60,8 @@ module rfnoc_block_fft_tb();    // Bus Functional Models    //--------------------------------------------------------------------------- -  typedef ChdrData #(CHDR_W, SAMP_W)::chdr_word_t chdr_word_t; +  typedef ChdrData #(CHDR_W, ITEM_W)::chdr_word_t chdr_word_t; +  typedef ChdrData #(CHDR_W, ITEM_W)::item_t      item_t;    RfnocBackendIf        backend            (rfnoc_chdr_clk, rfnoc_ctrl_clk);    AxiStreamIf #(32)     m_ctrl             (rfnoc_ctrl_clk, 1'b0); @@ -70,7 +70,7 @@ module rfnoc_block_fft_tb();    AxiStreamIf #(CHDR_W) s_chdr             (rfnoc_chdr_clk, 1'b0);    // Bus functional model for a software block controller -  RfnocBlockCtrlBfm #(CHDR_W, SAMP_W) blk_ctrl =  +  RfnocBlockCtrlBfm #(CHDR_W, ITEM_W) blk_ctrl =       new(backend, m_ctrl, s_ctrl);    // Connect block controller to BFMs @@ -141,9 +141,17 @@ module rfnoc_block_fft_tb();    // Test Process    //--------------------------------------------------------------------------- -  task automatic send_sine_wave ( +  task automatic test_sine_wave (      input int unsigned port    ); +    test.start_test("Test sine wave", 20us); + +    write_reg(port, DUT.SR_FFT_SIZE_LOG2, FFT_SIZE_LOG2); +    write_reg(port, DUT.SR_FFT_DIRECTION, DUT.FFT_FORWARD); +    write_reg(port, DUT.SR_FFT_SCALING, FFT_SCALING); +    write_reg(port, DUT.SR_FFT_SHIFT_CONFIG, FFT_SHIFT_CONFIG); +    write_reg(port, DUT.SR_MAGNITUDE_OUT, DUT.COMPLEX_OUT); // Enable real/imag out +      // Send a sine wave      fork        begin @@ -164,9 +172,9 @@ module rfnoc_block_fft_tb();        end        begin -        string s; -        chdr_word_t   recv_payload[$], temp_payload[$]; -        int           data_bytes; +        string       msg; +        chdr_word_t  recv_payload[$], temp_payload[$]; +        int          data_bytes;          logic [15:0] real_val;          logic [15:0] cplx_val; @@ -187,23 +195,184 @@ module rfnoc_block_fft_tb();                  // Assert that for the special case of a 1/8th sample rate sine wave input,                   // the real part of the corresponding 1/8th sample rate FFT bin should always be greater than 0 and                  // the complex part equal to 0. -                 -                `ASSERT_ERROR(real_val > 32'd0, "FFT bin real part is not greater than 0!"); -                `ASSERT_ERROR(cplx_val == 32'd0, "FFT bin complex part is not 0!"); +                $sformat(msg,  +                  "On iteration %0d, sample %0d, FFT real part is 0x%X, expected value > 0",  +                  n, 2*k+i, real_val); +                  `ASSERT_ERROR(real_val > 32'd0, msg); +                $sformat(msg, +                  "On iteration %0d, sample %0d, FFT complex part is 0x%X, expected 0",  +                  n, 2*k+i, cplx_val); +                  `ASSERT_ERROR(cplx_val == 32'd0, msg);                end else begin                  // Assert all other FFT bins should be 0 for both complex and real parts -                `ASSERT_ERROR(real_val == 32'd0, "FFT bin real part is not 0!"); -                `ASSERT_ERROR(cplx_val == 32'd0, "FFT bin complex part is not 0!"); +                $sformat(msg,  +                  "On iteration %0d, sample %0d, FFT real part is 0x%X, expected value 0",  +                  n, 2*k+i, real_val); +                  `ASSERT_ERROR(real_val == 32'd0, msg); +                $sformat(msg, +                  "On iteration %0d, sample %0d, FFT complex part is 0x%X, expected 0",  +                  n, 2*k+i, cplx_val); +                  `ASSERT_ERROR(cplx_val == 32'd0, msg);                end              end            end          end        end      join -  endtask + +    test.end_test(); +  endtask : test_sine_wave + + +  task automatic test_short ( +    input int unsigned port +  ); +    item_t samples[$], spectrum[$], recv[$]; +    string msg; + +    test.start_test("Test short FFT", 10us); + +    write_reg(port, DUT.SR_FFT_SIZE_LOG2, 3); +    write_reg(port, DUT.SR_FFT_DIRECTION, DUT.FFT_FORWARD); +    write_reg(port, DUT.SR_FFT_SCALING, 0);         // No scaling +    write_reg(port, DUT.SR_FFT_SHIFT_CONFIG, 10);   // Bypass shifting + +    // Samples to input to FFT (expected output of IFFT) +    samples = '{  +      32'h000E_0000,  // {16'd14, 16'd0}, // Vivado won't allow concatenation +      32'h000F_0000,  // {16'd15, 16'd0}, // in dynamic types. +      32'h0010_0000,  // {16'd16, 16'd0}, +      32'h0011_0000,  // {16'd17, 16'd0}, +      32'h0012_0000,  // {16'd18, 16'd0}, +      32'h0013_0000,  // {16'd19, 16'd0}, +      32'h0014_0000,  // {16'd20, 16'd0}, +      32'h0015_0000   // {16'd21, 16'd0} +    }; + +    // Expected spectrum output by FFT (values to input to IFFT) +    spectrum = '{  +      32'h008C_0000,  // { 16'sd140, 16'd0}, +      32'hFFFC_000A,  // {-16'sd4,   16'd10}, +      32'hFFFC_0004,  // {-16'sd4,   16'd4}, +      32'hFFFC_0002,  // {-16'sd4,   16'd2}, +      32'hFFFC_0000,  // {-16'sd4,   16'd0}, +      32'hFFFC_FFFE,  // {-16'sd4,  -16'd2}, +      32'hFFFC_FFFC,  // {-16'sd4,  -16'd4}, +      32'hFFFC_FFF6   // {-16'sd4,  -16'd10} +    }; + +    blk_ctrl.send_items(port, samples); +    blk_ctrl.recv_items(port, recv); + +    foreach (recv[i]) begin +      if (recv[i] != spectrum[i]) begin +        $sformat(msg, "On sample %d, received (%d,%d), expected (%d,%d)", i, +          signed'(recv[i][31:16]), signed'(recv[i][15:0]), +          signed'(spectrum[i][31:16]), signed'(spectrum[i][15:0])); +        `ASSERT_ERROR(0, msg); +      end +    end + +    test.end_test(); + +    test.start_test("Test short IFFT", 10us); + +    write_reg(port, DUT.SR_FFT_DIRECTION, DUT.FFT_REVERSE); +    write_reg(port, DUT.SR_FFT_SCALING, 12'b11); +    blk_ctrl.send_items(port, spectrum); +    blk_ctrl.recv_items(port, recv); + +    foreach (recv[i]) begin +      if (recv[i] != samples[i]) begin +        $sformat(msg, "On sample %d, received (%d,%d), expected (%d,%d)", i, +          signed'(recv[i][31:16]), signed'(recv[i][15:0]), +          signed'(samples[i][31:16]), signed'(samples[i][15:0])); +        `ASSERT_ERROR(0, msg); +      end +    end + +    test.end_test(); +  endtask : test_short + + +  task automatic test_regs ( +    input int unsigned port +  ); +    logic [31:0] val; + +    test.start_test("Test registers", 10us); + +    write_reg(port, DUT.SR_FFT_RESET, 1); +    write_reg(port, DUT.SR_FFT_RESET, 0); + +    // SR_FFT_SIZE_LOG2 +    read_user_reg(port, DUT.RB_FFT_SIZE_LOG2, val); +    `ASSERT_ERROR(val == DUT.DEFAULT_FFT_SIZE, "FFT_SIZE_LOG2 is incorrect"); +    write_reg(port, DUT.SR_FFT_SIZE_LOG2, 32'hFFFFFFFF); +    read_user_reg(port, DUT.RB_FFT_SIZE_LOG2, val); +    `ASSERT_ERROR(val == 32'hFF, "FFT_SIZE_LOG2 is incorrect"); +    write_reg(port, DUT.SR_FFT_SIZE_LOG2, 32'h0); +    read_user_reg(port, DUT.RB_FFT_SIZE_LOG2, val); +    `ASSERT_ERROR(val == 32'h0, "FFT_SIZE_LOG2 is incorrect"); +    write_reg(port, DUT.SR_FFT_SIZE_LOG2, DUT.DEFAULT_FFT_SIZE); +    read_user_reg(port, DUT.RB_FFT_SIZE_LOG2, val); +    `ASSERT_ERROR(val == DUT.DEFAULT_FFT_SIZE, "FFT_SIZE_LOG2 is incorrect"); + +    // SR_MAGNITUDE_OUT +    read_user_reg(port, DUT.RB_MAGNITUDE_OUT, val); +    `ASSERT_ERROR(val == 32'h0, "MAGNITUDE_OUT is incorrect"); +    write_reg(port, DUT.SR_MAGNITUDE_OUT, 32'hFFFFFFFF); +    read_user_reg(port, DUT.RB_MAGNITUDE_OUT, val); +    `ASSERT_ERROR(val == 32'h3, "MAGNITUDE_OUT is incorrect"); +    write_reg(port, DUT.SR_MAGNITUDE_OUT, 32'h0); +    read_user_reg(port, DUT.RB_MAGNITUDE_OUT, val); +    `ASSERT_ERROR(val == 32'h0, "MAGNITUDE_OUT is incorrect"); + +    // SR_FFT_DIRECTION +    read_user_reg(port, DUT.RB_FFT_DIRECTION, val); +    `ASSERT_ERROR(val == DUT.DEFAULT_FFT_DIRECTION, "FFT_DIRECTION is incorrect"); +    write_reg(port, DUT.SR_FFT_DIRECTION, 32'hFFFFFFFF); +    read_user_reg(port, DUT.RB_FFT_DIRECTION, val); +    `ASSERT_ERROR(val == 32'h1, "FFT_DIRECTION is incorrect"); +    write_reg(port, DUT.SR_FFT_DIRECTION, 32'h0); +    read_user_reg(port, DUT.RB_FFT_DIRECTION, val); +    `ASSERT_ERROR(val == 32'h0, "FFT_DIRECTION is incorrect"); +    write_reg(port, DUT.SR_FFT_DIRECTION, DUT.DEFAULT_FFT_DIRECTION); +    read_user_reg(port, DUT.RB_FFT_DIRECTION, val); +    `ASSERT_ERROR(val == DUT.DEFAULT_FFT_DIRECTION, "FFT_DIRECTION is incorrect"); + +    // SR_FFT_SCALING +    read_user_reg(port, DUT.RB_FFT_SCALING, val); +    `ASSERT_ERROR(val == DUT.DEFAULT_FFT_SCALING, "FFT_SCALING is incorrect"); +    write_reg(port, DUT.SR_FFT_SCALING, 32'hFFFFFFFF); +    read_user_reg(port, DUT.RB_FFT_SCALING, val); +    `ASSERT_ERROR(val == 32'hFFF, "FFT_SCALING is incorrect"); +    write_reg(port, DUT.SR_FFT_SCALING, 32'h0); +    read_user_reg(port, DUT.RB_FFT_SCALING, val); +    `ASSERT_ERROR(val == 32'h0, "FFT_SCALING is incorrect"); +    write_reg(port, DUT.SR_FFT_SCALING, DUT.DEFAULT_FFT_SCALING); +    read_user_reg(port, DUT.RB_FFT_SCALING, val); +    `ASSERT_ERROR(val == DUT.DEFAULT_FFT_SCALING, "FFT_SCALING is incorrect"); + +    // SR_FFT_SHIFT_CONFIG +    read_user_reg(port, DUT.RB_FFT_SHIFT_CONFIG, val); +    `ASSERT_ERROR(val == 32'b0, "FFT_SHIFT_CONFIG is incorrect"); +    write_reg(port, DUT.SR_FFT_SHIFT_CONFIG, 32'hFFFFFFFF); +    read_user_reg(port, DUT.RB_FFT_SHIFT_CONFIG, val); +    `ASSERT_ERROR(val == 32'h3, "FFT_SHIFT_CONFIG is incorrect"); +    write_reg(port, DUT.SR_FFT_SHIFT_CONFIG, 32'h0); +    read_user_reg(port, DUT.RB_FFT_SHIFT_CONFIG, val); +    `ASSERT_ERROR(val == 32'h0, "FFT_SHIFT_CONFIG is incorrect"); +    write_reg(port, DUT.SR_FFT_SHIFT_CONFIG, 32'b0); +    read_user_reg(port, DUT.RB_FFT_SHIFT_CONFIG, val); +    `ASSERT_ERROR(val == 32'b0, "FFT_SHIFT_CONFIG is incorrect"); + +    test.end_test(); +  endtask : test_regs +    initial begin : tb_main -    const int port = 0; +    static int port = 0;      test.start_tb("rfnoc_block_fft_tb");      // Start the BFMs running @@ -233,24 +402,12 @@ module rfnoc_block_fft_tb();      test.end_test();      //------------------------------------------------------------------------- -    // Setup FFT +    // Tests      //------------------------------------------------------------------------- -    test.start_test("Setup FFT", 10us); -    write_reg(port, DUT.SR_FFT_SIZE_LOG2, FFT_SIZE_LOG2); -    write_reg(port, DUT.SR_FFT_DIRECTION, FFT_DIRECTION); -    write_reg(port, DUT.SR_FFT_SCALING, FFT_SCALING); -    write_reg(port, DUT.SR_FFT_SHIFT_CONFIG, FFT_SHIFT_CONFIG); -    write_reg(port, DUT.SR_MAGNITUDE_OUT, DUT.COMPLEX_OUT); // Enable real/imag out -    test.end_test(); - -    //-------------------------------------------------------------------------76 -    // Test sine wave -    //------------------------------------------------------------------------- - -    test.start_test("Test sine wave", 20us); -    send_sine_wave (port); -    test.end_test(); +    test_regs(port); +    test_short(port); +    test_sine_wave(port);      //-------------------------------------------------------------------------      // Finish | 
