Converted Verilog Outputs Different Result Compared to Original SysVerilog
marchuang6272 opened this issue · 3 comments
Hello! I used this repo to convert my adder_tree.sv into adder_tree.v. I ran the same testbench for both modules and got different outputs. Could I get help on this issue? Thanks. The adder tree simply adds of its inputs together. The testbench should output 28.
Here is the converted Verilog code from sv2v
module adder_tree ( clk, nrst, idata, odata ); parameter INPUTS_NUM = 125; parameter IDATA_WIDTH = 16; parameter STAGES_NUM = $clog2(INPUTS_NUM); parameter INPUTS_NUM_INT = 2 ** STAGES_NUM; parameter ODATA_WIDTH = IDATA_WIDTH + STAGES_NUM; input clk; input nrst; input wire [(INPUTS_NUM * IDATA_WIDTH) - 1:0] idata; output wire [ODATA_WIDTH - 1:0] odata; reg [((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) - (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT)) + 1) * ODATA_WIDTH) + (((STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) * ODATA_WIDTH) - 1) : ((((STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1))) + 1) * ODATA_WIDTH) + (((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) * ODATA_WIDTH) - 1)):((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) * ODATA_WIDTH : (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) * ODATA_WIDTH)] data; genvar _gv_stage_1; genvar _gv_adder_1; generate for (_gv_stage_1 = 0; _gv_stage_1 <= STAGES_NUM; _gv_stage_1 = _gv_stage_1 + 1) begin : stage_gen localparam stage = _gv_stage_1; localparam ST_OUT_NUM = INPUTS_NUM_INT >> stage; localparam ST_WIDTH = IDATA_WIDTH + stage; if (stage == {32 {1'sb0}}) begin : genblk1 for (_gv_adder_1 = 0; _gv_adder_1 < ST_OUT_NUM; _gv_adder_1 = _gv_adder_1 + 1) begin : inputs_gen localparam adder = _gv_adder_1; always @(*) if (adder < INPUTS_NUM) begin data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + (ST_WIDTH - 1)-:ST_WIDTH] <= idata[(adder * IDATA_WIDTH) + (ST_WIDTH - 1)-:ST_WIDTH]; data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + ((ODATA_WIDTH - 1) >= ST_WIDTH ? ODATA_WIDTH - 1 : ((ODATA_WIDTH - 1) + ((ODATA_WIDTH - 1) >= ST_WIDTH ? ((ODATA_WIDTH - 1) - ST_WIDTH) + 1 : (ST_WIDTH - (ODATA_WIDTH - 1)) + 1)) - 1)-:((ODATA_WIDTH - 1) >= ST_WIDTH ? ((ODATA_WIDTH - 1) - ST_WIDTH) + 1 : (ST_WIDTH - (ODATA_WIDTH - 1)) + 1)] <= 1'sb0; end else data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + (ODATA_WIDTH - 1)-:ODATA_WIDTH] <= 1'sb0; end end else begin : genblk1 for (_gv_adder_1 = 0; _gv_adder_1 < ST_OUT_NUM; _gv_adder_1 = _gv_adder_1 + 1) begin : adder_gen localparam adder = _gv_adder_1; always @(posedge clk) if (~nrst) data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + (ODATA_WIDTH - 1)-:ODATA_WIDTH] <= 1'sb0; else data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage : STAGES_NUM - stage) * INPUTS_NUM_INT) + adder) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + (ST_WIDTH - 1)-:ST_WIDTH] <= data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage - 1 : STAGES_NUM - (stage - 1)) * INPUTS_NUM_INT) + (adder * 2) : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage - 1 : STAGES_NUM - (stage - 1)) * INPUTS_NUM_INT) + (adder * 2)) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + ((ST_WIDTH - 2) >= 0 ? ST_WIDTH - 2 : ((ST_WIDTH - 2) + ((ST_WIDTH - 2) >= 0 ? ST_WIDTH - 1 : 3 - ST_WIDTH)) - 1)-:((ST_WIDTH - 2) >= 0 ? ST_WIDTH - 1 : 3 - ST_WIDTH)] + data[(((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? ((STAGES_NUM >= 0 ? stage - 1 : STAGES_NUM - (stage - 1)) * INPUTS_NUM_INT) + ((adder * 2) + 1) : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - ((((STAGES_NUM >= 0 ? stage - 1 : STAGES_NUM - (stage - 1)) * INPUTS_NUM_INT) + ((adder * 2) + 1)) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH) + ((ST_WIDTH - 2) >= 0 ? ST_WIDTH - 2 : ((ST_WIDTH - 2) + ((ST_WIDTH - 2) >= 0 ? ST_WIDTH - 1 : 3 - ST_WIDTH)) - 1)-:((ST_WIDTH - 2) >= 0 ? ST_WIDTH - 1 : 3 - ST_WIDTH)]; end end end endgenerate assign odata = data[((STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)) >= (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) ? (STAGES_NUM >= 0 ? STAGES_NUM : STAGES_NUM - STAGES_NUM) * INPUTS_NUM_INT : (STAGES_NUM >= 0 ? 0 : STAGES_NUM * INPUTS_NUM_INT) - (((STAGES_NUM >= 0 ? STAGES_NUM : STAGES_NUM - STAGES_NUM) * INPUTS_NUM_INT) - (STAGES_NUM >= 0 ? ((STAGES_NUM + 1) * INPUTS_NUM_INT) - 1 : ((1 - STAGES_NUM) * INPUTS_NUM_INT) + ((STAGES_NUM * INPUTS_NUM_INT) - 1)))) * ODATA_WIDTH+:ODATA_WIDTH]; endmodule
and its original SystemVerilog counterpart:
`module adder_tree #(
parameter INPUTS_NUM = 125,
parameter IDATA_WIDTH = 16,
parameter STAGES_NUM = $clog2(INPUTS_NUM),
parameter INPUTS_NUM_INT = 2 ** STAGES_NUM,
parameter ODATA_WIDTH = IDATA_WIDTH + STAGES_NUM
)(
input clk,
input nrst,
input logic [INPUTS_NUM-1:0][IDATA_WIDTH-1:0] idata,
output logic [ODATA_WIDTH-1:0] odata
);
logic [STAGES_NUM:0][INPUTS_NUM_INT-1:0][ODATA_WIDTH-1:0] data;
// generating tree
genvar stage, adder;
generate
for( stage = 0; stage <= STAGES_NUM; stage++ ) begin: stage_gen
localparam ST_OUT_NUM = INPUTS_NUM_INT >> stage;
localparam ST_WIDTH = IDATA_WIDTH + stage;
if( stage == '0 ) begin
// stege 0 is actually module inputs
for( adder = 0; adder < ST_OUT_NUM; adder++ ) begin: inputs_gen
always_comb begin
if( adder < INPUTS_NUM ) begin
data[stage][adder][ST_WIDTH-1:0] <= idata[adder][ST_WIDTH-1:0];
data[stage][adder][ODATA_WIDTH-1:ST_WIDTH] <= '0;
end else begin
data[stage][adder][ODATA_WIDTH-1:0] <= '0;
end
end // always_comb
end // for
end else begin
// all other stages hold adders outputs
for( adder = 0; adder < ST_OUT_NUM; adder++ ) begin: adder_gen
//always_comb begin // is also possible here
always_ff@(posedge clk) begin
if( ~nrst ) begin
data[stage][adder][ODATA_WIDTH-1:0] <= '0;
end else begin
data[stage][adder][ST_WIDTH-1:0] <=
data[stage-1][adder*2][(ST_WIDTH-1)-1:0] +
data[stage-1][adder*2+1][(ST_WIDTH-1)-1:0];
end
end // always
end // for
end // if stage
end // for
endgenerate
assign odata = data[STAGES_NUM][0];
endmodule
`
lastly, here is the testbench I use to test both.
`
`timescale 1ns / 1ps
module adder_tree_tb();
logic rst;
initial begin
#0 rst = 1'b1;
#10 rst = 1'b0;
#5 rst = 1'b1;
end
logic clk;
initial begin
#0 clk = 1'b0;
forever
#2.5 clk = ~clk;
end
// Module under test ==========================================================
initial begin
#30 $display("%0d", at.odata);
end
adder_tree #(
.INPUTS_NUM( 7 ),
.IDATA_WIDTH( 16 )
) at (
.clk( clk ),
.nrst( rst),
.idata( { 16'd1,
16'd2,
16'd3,
16'd4,
16'd5,
16'd6,
16'd7 }),
.odata()
);
endmodule
`
Thank you for filing this issue! The difference results from a shortcoming in sv2v's conversion of always_comb
, where the resulting always
block doesn't necessarily execute at time zero as the standard requires.
You have three options:
- If your downstream flow supports
always_comb
(Yosys does), you can pass-E always
to sv2v to exclude the problematic conversion. - Wait a couple weeks to give me time to fix the issue in sv2v. I may do this by generating a synthetic variable to trigger the
always
block at time zero, similar to the way processes are handled in the Yosys Verilog backend. - You can change your code (temporarily) to workaround the issue, e.g., by moving the
else data[stage][adder][ODATA_WIDTH-1:0] <= '0;
into aninitial
block.
@marchuang6272 I just pushed f9917d9, which ensures that always_comb
and always_latch
execute at time zero. I confirmed your test case now produces the expected output when converted. Please let me know if it works for you. Thank you!
I'm closing this because this issue should be resolved. I appreciate you taking the time to file an issue! Please feel free to reopen or open a new issue as appropriate.