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:
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.
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
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.