Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Function returning logically incorrect values

I am currently learning to write Verilog and as an exercise trying to implement an algorithm, but a function I have written for it returns unexpected, incorrect values.

I managed to reduce it to this minimal example:

function [0:1] test (
    input a0,
    input a1,
    input r
);                                                                                                         
    begin
        test = {(a0 ^ 1) & r, (a1 ^ 1) & r};
    end
endfunction

which I then call inside a module:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

assign out[1:0] = test(0, 0, 1);

where out is the output register of the module.

To my understanding both out[1] and out[0] should then have the same value, namely 1 (since (0 ^ 1) & 1 = 1).

I wrote a testbench for this and if I simply call this module there once, the wave output of my IDE shows me that out[1] and out[0] are now 0 and 1, respectively, as can be seen in the wave in the screenshot.

wave output of testbench

Logically, this does not make sense so there must be another issue I am missing but I am at a complete loss what it could be. Any help would be greatly appreciated.

The entire code I’m using to reproduce this error:

issue.v

module issue(
    input [63:0] in,
    input [63:0] mask,
    input [63:0] r,
    output reg [63:0] out
);

    function [0:1] test (
        input a0,
        input a1,
        input r
    );
        begin
            test = {(a0 ^ 1) & r, (a1 ^ 1) & r};
        end
    endfunction

    assign out[1:0] = test(0, 0, 1);

endmodule

issue_tb.v

`timescale 1 ns/10 ps

module issue_tb;
    localparam period = 20;

    reg [63:0] in, mask, r;
    wire [63:0] out;

    issue UUT  (.in(in), .mask(mask), .r(r), .out(out));

    reg clk;

    always begin
        clk = 1'b1; 
        #20; // high for 20 * timescale = 20 ns

        clk = 1'b0;
        #20; // low for 20 * timescale = 20 ns
    end

    always @(posedge clk)
    begin
        // test 0
        //in = 63'h0;
        //mask = 63'h0;
        //r = 63'h1;
        #period;
        if(!(out == 63'h0)) begin
            $display("Test 0 failed");
            $stop;
        end
        $display("All tests passed");
        $stop;
    end
endmodule

>Solution :

The problem is that the constant 1 is not 1-bit wide, as you require.

Change:

    test = {(a0 ^ 1) & r, (a1 ^ 1) & r};

to:

    test = {(a0 ^ 1'b1) & r, (a1 ^ 1'b1) & r};

There are subtleties associated with using the concatenation operator ({}) regarding signal bit widths. Refer to IEEE Std 1800-2017, Table 11-21— Bit lengths resulting from self-determined expressions. The problem with your code is that items in a concatenation are self-determined. I believe 1 is 32 bits wide. So, each of the 2 expressions in the concatenation is 32 bits wide, thereby truncating bits for test, which is only 2 bits wide. Using 1'b1 sets the bit width of the constant to 1.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading