Question

A couple of days ago I asked about a module (here) I wanted to implement which takes the MSB of input samples, accumulates them (by shifting) and combines them into the output sample when the 32 output bit is "filled".

Thanks to the help there, I got this implementation, which doesn't produce any compilation errors and seemed fine with Xilinx 12.1:

module my_rx_dsp0
#(
    //frontend bus width
    parameter WIDTH = 24
)
(
    //control signals
    input clock, //dsp clock
    input reset, //active high synchronous reset
    input clear, //active high on packet control init
    input enable, //active high when streaming enabled

    //user settings bus, controlled through user setting regs API
    input set_stb, input [7:0] set_addr, input [31:0] set_data,

    //full rate inputs directly from the RX frontend
    input [WIDTH-1:0] frontend_i,
    input [WIDTH-1:0] frontend_q,

    //full rate outputs directly to the DDC chain
    output [WIDTH-1:0] ddc_in_i,
    output [WIDTH-1:0] ddc_in_q,

    //strobed samples {I16,Q16} from the RX DDC chain
    input [31:0] ddc_out_sample,
    input ddc_out_strobe, //high on valid sample
    output ddc_out_enable, //enables DDC module

    //strobbed baseband samples {I16,Q16} from this module
    output reg [31:0] bb_sample,
    output reg bb_strobe //high on valid sample
);

    reg [3:0] i_msb;
    reg [3:0] q_msb;

    reg [31:0] temp_buff = 0;
    reg [1:0] count = 0;

    always @(posedge clock) begin 
        if(ddc_out_strobe) begin
            // bit shifter for MSB
            temp_buff <= {i_msb,q_msb,temp_buff[31:8]};
            // to avoid if-else condition
            count <= (count==2'd3) ? 2'd0 : (count+1);
        end
    end

    always @(*) begin
        i_msb = ddc_out_sample[31:28];
        q_msb = ddc_out_sample[15:12];
        // to avoid if-else condition   
        bb_strobe = (count==2'd3);
        bb_sample = bb_strobe ? temp_buff : 32'd0;  
    end

    assign ddc_in_i = frontend_i;
    assign ddc_in_q = frontend_q;
    assign ddc_out_enable = enable; 

endmodule //my_rx_dsp0_custom

Now I wanted to implement a testbench that tests my_rx_dsp0.v with some examples. I implemented a my_rx_dsp0_tb_2.v, which reads 32 bit samples from a file named my_input.dat to feed to the module as inputs ddc_out_sample. They are then compared to the correct values stored at my_output.dat.

Note: I did not write this testbench myself, I adapted it from another testbench from an open-source project.

Here is the implementation:

module my_rx_dsp0_tb ( );

reg clk;
reg reset;
reg enable;
reg ddc_out_strobe; //high on valid sample
reg [31:0] ddc_out_sample;
wire [31:0] bb_sample = 32'd0;
wire bb_strobe;
wire ddc_out_enable = 1'b1; //enables DDC module

parameter WIDTH = 24;
parameter clocks = 2; // number of clocks per input

reg endofsim = 0;
integer number_of_errors;
initial number_of_errors = 0;

wire set_stb = 1;
wire [7:0] set_addr;
wire [31:0] set_data;
wire [WIDTH-1:0] frontend_i;
wire [WIDTH-1:0] frontend_q;
wire [WIDTH-1:0] ddc_in_i;
wire [WIDTH-1:0] ddc_in_q;

reg signed [31:0] compare_out;

// Setup the clock
initial clk = 1'b0;
always #5 clk <= ~clk ;

// Come out of reset after a while
initial reset = 1'b1 ;
initial #1000 reset = 1'b0 ;

// Enable the entire system
initial enable = 1'b1 ;

// Instantiate UUT
my_rx_dsp0 #(.WIDTH(WIDTH)) UUT_rx_dsp0
    (   .clock(clk), .reset(reset), .clear(clear), .enable(enable),
        .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
        .frontend_i(frontend_i), .frontend_q(frontend_q),
        .ddc_in_i(ddc_in_i), .ddc_in_q(ddc_in_q),
        .ddc_out_sample(ddc_out_sample), .ddc_out_strobe(ddc_out_strobe), .ddc_out_enable(ddc_out_enable),
        .bb_sample(bb_sample), .bb_strobe(bb_strobe) );

//-------Setup file IO-------//
//
integer i, r_in, r_out, infile, outfile;

initial begin
    infile = $fopen("my_input.dat","r");
    outfile = $fopen("my_output.dat","r");
    $timeformat(-9, 2, " ns", 10) ;
    // for n=9,p=2 digits after decimal pointer
    //min_field_width=10 number of character positions for %t
end      

//-------Get sim values and display errors-------//
//
initial begin
    // Initialize inputs
    ddc_out_strobe <= 1'd0;
    ddc_out_sample <= 32'd0;

    // Wait for reset to go away
    @(negedge reset) #0;

    while(!endofsim) begin
        // Write the input from the file or 0 if EndOfFile(EOF)
        @(posedge clk) begin
            #1
            ddc_out_strobe <= 1'b1;
            if(!$feof(infile))
                r_in = $fscanf(infile,"%b\n",ddc_out_sample);
            else
                ddc_out_sample <= 32'd0;
        end
        //
        // Clocked in; set the strobe to 0 if the # of clocks/sample
        // is greater than 1
        if( clocks > 1 ) begin
            @(posedge clk) begin
                ddc_out_strobe <= 1'b0  ;
            end

            // Wait for the specified # of cycles
            for( i = 0 ; i < (clocks-2) ; i = i + 1 ) begin
                @(posedge clk) #1 ;
            end
        end
        //

        //
        // Print out the number of errors that occured
        if(number_of_errors) begin
            $display("FAILED: %d errors during simulation",number_of_errors) ;
        end else begin
            $display("PASSED: Simulation successful") ;
        end 
        // 
    end 
end

//-------Comparison btwn simulated values vs known good values-------//
//
always @(posedge clk) begin
    if(reset)
        endofsim <= 1'b0 ;
    else begin
        if(!$feof(outfile)) begin
            if(bb_strobe) begin
                r_out = $fscanf(outfile,"%b\n",compare_out);
                if(compare_out != bb_sample) begin
                    $display("%t: %b != %b",$realtime,bb_sample,compare_out);
                    number_of_errors = number_of_errors + 1;
                end else begin
                    $display("%t: %b = %b",$realtime,bb_sample,compare_out);
                end
            end
        end else begin
            // Signal end of simulation when no more outputs
            endofsim <= 1'b1 ;
        end
    end
end 

endmodule // my_rx_dsp0_tb

When simulating with ISim from Xilinx ISE Suite Edition 12.1 I do not get the desired functionality from the module. I am afraid the output contains several x states (unknown states), instead of 1s or 0s as expected.

Question Is this due to:

1) The way the files are being read with $fscanf?

2) Did I wrong by initializing reg [31:0] temp_buff = 0?

3) Or does someone have an idea on what went wrong?

The error prompts from the testbench are (as an example): xx000x00xxx00x0xx000x0x000000000 != 10000110111001011100010001101100

Was it helpful?

Solution

The X is from having multiple conflicting drivers on bb_sample and ddc_out_enable. The wire type merges the drivers, conflicting bit values of the same strength resolve as X.

UUT_rx_dsp0 is the intended diver. However you added and additional drivers from the way you declared your wires.

...
wire [31:0] bb_sample = 32'd0; // "= 32'd0" is a continuous driver
wire bb_strobe;
wire ddc_out_enable = 1'b1; // "= 1'd1" is a continuous driver
...

What you want is:

...
wire [31:0] bb_sample;
wire bb_strobe;
wire ddc_out_enable;
...

Correcting the above will resolve the X issue. Based on the example error it looks like are data miss matches. With the provided information, it is hard to tell it if it a test-bench or design issue. Could be just clock or propagation skew.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top