// // Copyright 2022 Ettus Research, A National Instruments Brand // // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: sim_radio_gen // // Description: // // Generate radio data for simulation purposes. The strobe pattern is random, // which is not like a normal radio but covers every possibility. The data // pattern is an incrementing sequence of samples, with each channel starting // at a different value to differentiate them. Strobe and time are common // between channels. // // The initial rx_data and radio_time values can be set at run-time using the // functions provided. // // Parameters: // // NSPC : Number of samples per clock cycle // SAMP_W : Length of each radio sample // NUM_CHANNELS : Number of radio RX ports // STB_PROB : Probability of STB being asserted on each clock cycle // INCREMENT : Amount by which to increment radio time each strobe // module sim_radio_gen #( parameter int NSPC = 1, parameter int SAMP_W = 32, parameter int NUM_CHANNELS = 1, parameter int STB_PROB = 50, parameter int INCREMENT = NSPC, localparam int RADIO_W = SAMP_W*NSPC ) ( input logic radio_clk, input logic radio_rst, output logic [NUM_CHANNELS-1:0][RADIO_W-1:0] radio_rx_data, output logic [ NUM_CHANNELS-1:0] radio_rx_stb, output logic [ 63:0] radio_time ); typedef bit [ SAMP_W-1:0] sample_t; // Single sample typedef sample_t [ NSPC-1:0] radio_t; // Radio output word typedef radio_t [NUM_CHANNELS-1:0] data_t; // Radio output for all channels typedef bit [ 63:0] timestamp_t; // Radio timestamp //--------------------------------------------------------------------------- // Functions //--------------------------------------------------------------------------- // Generate initial value for a single radio channel function radio_t radio_init( sample_t first_sample = '0 ); radio_t ret_val; for (int samp_i = 0; samp_i < NSPC; samp_i++) begin ret_val[samp_i] = first_sample + samp_i; end return ret_val; endfunction : radio_init // Generate an initial value all radio channels function radio_t [NUM_CHANNELS-1:0] radio_init_all( bit [SAMP_W-1:0] first_sample = '0 ); data_t ret_val; sample_t sample; // Calculate the value of subsequent samples in the channel for (int ch_i = 0; ch_i < NUM_CHANNELS; ch_i++) begin sample = sample_t'((2.0 ** SAMP_W) / NUM_CHANNELS * ch_i + first_sample); ret_val[ch_i] = radio_init(first_sample); end return ret_val; endfunction : radio_init_all timestamp_t next_time = '0; bit next_time_ld = 0; radio_t [NUM_CHANNELS-1:0] next_data = '0; bit [NUM_CHANNELS-1:0] next_data_ld = '0; // Change the radio time on the next clock edge function void set_time(timestamp_t timestamp); next_time = timestamp; next_time_ld = 1; endfunction : set_time // Change the radio data value for the given channel on the next clock edge function void set_data( int channel, radio_t data); next_data [channel] = data; next_data_ld[channel] = 1; endfunction : set_data // Change the radio data value for all channels on the next clock edge function void set_data_all( data_t data); next_data = data; next_data_ld = '1; endfunction : set_data_all //--------------------------------------------------------------------------- // Radio Output Generation //--------------------------------------------------------------------------- radio_t [NUM_CHANNELS-1:0] reg_data = radio_init_all(); timestamp_t reg_time = '0; // Output X when strobe is low to cause errors when we use the time or data // during the wrong clock cycle. assign radio_rx_data = radio_rx_stb ? reg_data : 'X; assign radio_time = radio_rx_stb ? reg_time : 'X; always @(posedge radio_clk) begin : radio_data_count_reg if (radio_rst) begin reg_data <= radio_init(); radio_rx_stb <= '0; reg_time <= '0; end else begin radio_rx_stb <= '0; if ($urandom_range(99) < STB_PROB) begin for (int ch_i = 0; ch_i < NUM_CHANNELS; ch_i++) begin for (int samp_i = 0; samp_i < NSPC; samp_i++) begin reg_data[ch_i][samp_i] = reg_data[ch_i][samp_i] + NSPC; end end reg_time <= reg_time + INCREMENT; radio_rx_stb <= '1; end // Override the radio data if (next_data_ld) begin for (int ch_i=0; ch_i < NUM_CHANNELS; ch_i++) begin if (next_data_ld[ch_i]) reg_data[ch_i] <= next_data[ch_i]; end next_data_ld = 0; end // Override the radio time if (next_time_ld) begin reg_time <= next_time; next_time_ld = 0; end end end : radio_data_count_reg endmodule : sim_radio_gen