0
\$\begingroup\$

I wrote SystemVerilog code that gets an input and connects it to a chain of registers (i.e., a "word shift register").

The output is an array whose size equals the number of registers + 1. The output's zero index is simply a wire that's driven by the input. This is my code:

module register_chain
#(
    parameter NUMBER_REGISTERS = 31 ,
    parameter WIDTH_REGISTER = 12
)
(
    input INPUT_CLOCK ,
    input [ WIDTH_REGISTER - 1 : 0 ] INPUT_DATA ,
    input INPUT_ENABLE ,
    input INPUT_RESET ,

    output logic [ 0 : NUMBER_REGISTERS ] [ WIDTH_REGISTER - 1 : 0 ] OUTPUT_DATA
) ;

logic [ 0 : NUMBER_REGISTERS - 1 ] [ WIDTH_REGISTER - 1 : 0 ] array_registers_data ;

    assign OUTPUT_DATA = { INPUT_DATA , array_registers_data } ;
    
    always_ff @ ( posedge INPUT_CLOCK )
    begin : registering
        if ( INPUT_RESET == 1'b1 ) begin
            array_registers_data <= '{ default : '0 } ;
        end else if ( INPUT_ENABLE == 1'b1 ) begin
            array_registers_data <= { INPUT_DATA , array_registers_data [ 0 : NUMBER_REGISTERS - 2 ] } ;
        end
    end : registering

endmodule

I'm seeing very strange behavior in my simulator:

OUTPUT_DATA[0] is the same as the input INPUT_DATA (as it should be).

OUTPUT_DATA[1] is also the same as the input INPUT_DATA (which is a bug).

OUTPUT_DATA [ 2 ... n ] get the delayed copies of INPUT_DATA as they should.

Do you see something wrong in my code?

enter image description here

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Show us your testbench. There's probably a subtle problem with how you're generating INPUT_DATA -- it may be changing just before the clock edge (rather than being driven by the clock), so it is captured essentially immediately by the register array. \$\endgroup\$
    – Dave Tweed
    Commented Sep 19, 2020 at 1:43
  • \$\begingroup\$ INPUT_DATA is generated synchronously inside an always_ff block driven by the same INPUT_CLOCK as the register chain module. \$\endgroup\$
    – shaiko
    Commented Sep 19, 2020 at 9:31

1 Answer 1

1
\$\begingroup\$

Perhaps there is a bug in your simulator. This testbench works on edaplayground:

module register_chain
#(
    parameter NUMBER_REGISTERS = 31 ,
    parameter WIDTH_REGISTER = 12
)
(
    input INPUT_CLOCK ,
    input [ WIDTH_REGISTER - 1 : 0 ] INPUT_DATA ,
    input INPUT_ENABLE ,
    input INPUT_RESET ,

    output logic [ 0 : NUMBER_REGISTERS ] [ WIDTH_REGISTER - 1 : 0 ] OUTPUT_DATA
) ;

logic [ 0 : NUMBER_REGISTERS - 1 ] [ WIDTH_REGISTER - 1 : 0 ] array_registers_data ;

    assign OUTPUT_DATA = { INPUT_DATA , array_registers_data } ;
    
    always_ff @ ( posedge INPUT_CLOCK )
    begin : registering
        if ( INPUT_RESET == 1'b1 ) begin
            array_registers_data <= '{ default : '0 } ;
        end else if ( INPUT_ENABLE == 1'b1 ) begin
            array_registers_data <= { INPUT_DATA , array_registers_data [ 0 : NUMBER_REGISTERS - 2 ] } ;
        end
    end : registering

endmodule

module tb;
    parameter NUMBER_REGISTERS = 31;
    parameter WIDTH_REGISTER   = 12;

    bit INPUT_CLOCK;
    bit [WIDTH_REGISTER-1:0] INPUT_DATA;
    bit INPUT_ENABLE = 1;
    bit INPUT_RESET  = 1;
    wire [0:NUMBER_REGISTERS][WIDTH_REGISTER-1:0] OUTPUT_DATA;

register_chain #(
    .NUMBER_REGISTERS(NUMBER_REGISTERS),
    .WIDTH_REGISTER  (WIDTH_REGISTER)
)
dut (
    .INPUT_CLOCK   (INPUT_CLOCK),
    .INPUT_DATA    (INPUT_DATA),
    .INPUT_ENABLE  (INPUT_ENABLE),
    .INPUT_RESET   (INPUT_RESET),
    .OUTPUT_DATA   (OUTPUT_DATA)
);

always #5 INPUT_CLOCK++;

always_ff @ ( posedge INPUT_CLOCK ) begin
    INPUT_DATA <= $urandom;
end

always @ (negedge INPUT_CLOCK) begin
    if (!INPUT_RESET) begin
        $display($time, "  OUTPUT_DATA [0]='h%x, [1]='h%x", OUTPUT_DATA[0], OUTPUT_DATA[1]);
    end
end

initial begin
    #23 INPUT_RESET = 0;
    #100 $finish;
end

endmodule

Here is some sample output I get, where [0] and [1] are different:

              30  OUTPUT_DATA [0]='h57f, [1]='h997
              40  OUTPUT_DATA [0]='hf4c, [1]='h57f
              50  OUTPUT_DATA [0]='h1a9, [1]='hf4c
              60  OUTPUT_DATA [0]='he0a, [1]='h1a9
              70  OUTPUT_DATA [0]='he5d, [1]='he0a
              80  OUTPUT_DATA [0]='h445, [1]='he5d
              90  OUTPUT_DATA [0]='h941, [1]='h445
             100  OUTPUT_DATA [0]='hbfc, [1]='h941
             110  OUTPUT_DATA [0]='h08b, [1]='hbfc
             120  OUTPUT_DATA [0]='hca1, [1]='h08b
\$\endgroup\$
4
  • \$\begingroup\$ This is what I also think. Thanks a lot for taking the time to test it yourself. \$\endgroup\$
    – shaiko
    Commented Sep 19, 2020 at 19:16
  • 2
    \$\begingroup\$ @shaiko: You're welcome. Does this code work on your simulator? \$\endgroup\$
    – toolic
    Commented Sep 19, 2020 at 19:29
  • \$\begingroup\$ With the above code I see the same problem. But I was able to "solve" it by driving INPUT_DATA through a temporary signal and driving the internal logic with that temporary signal (instead of INPUT_DATA directly). I'm pretty sure it's a simulation bug. \$\endgroup\$
    – shaiko
    Commented Sep 19, 2020 at 23:03
  • \$\begingroup\$ @shaiko, I have simulated it on Vivado simulator using the testbench code by toolic. The design works as intended. A bug in the simulator is very unlikely, unless you can share the version of the simulator you have used. If there is a bug, we should report it on Xilinx's forums. \$\endgroup\$ Commented Sep 23, 2020 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.