Creating SystemVerilog module using for loop and separate custom module

system-verilog

I am trying to create an n-bit barrel shifter using the diagram in the answer to this question: https://stackoverflow.com/questions/26551049/vhdl-n-bit-barrel-shifter

I've read that if the variable in a for loop has a single name, then each loop iteration has a separate scope and a separate variable; however, I'm not sure whether the rows in my barrel module will be created in the same style as the reference diagram from above. This is my barrel module:

module barrel
    #(parameter n = 8; parameter control = $clog2(n))
    (input logic[n-1:0] data, input logic [control-1:0] select,
    output logic [n-1:0] result);

    for(genvar i = 0; i < control; i++) begin : label
            logic [n-1:0] tempResult;

            always_comb
                    if(i == 0) row #(n,2**i) shiftLevel(data,select[i],tempResult);
                    else if(i == control-1) row #(n,2**i) shiftLevel(label[i-1].shiftLevel.tempResult,select[i],result);
                    else row #(n,2**i) shiftLevel(label[i-1].shiftLevel.tempResult,select[i],tempResult);
    end

endmodule

My question is this: will the labeled for loop preserve the row modules that I create in each iteration? Or does each row get destroyed once the iteration finishes?

Here are the other modules that I'm using to implement this:

row module:

module row
    #(parameter n=8, parameter shift=4) // n is the number of bits
                                            // shift is the max amount of shift at this level
    (input logic [n-1:0] data,
    input logic select,
    output logic [n-1:0] end);

    for(genvar i = 0; i < n; i++) begin : label
            logic [1:0] dataTemp;

            always_comb
                    dataTemp[0] <= data[i]; // 0 option of the mux is set to the normal data value

                    if(i+shift < n) dataTemp[1] <= data[i+shift]; // assigns the shifted bit
                    else dataTemp[0] <= 0; // assigns 0

            mux2 bit(dataTemp,select,end[i]); // Assembles a mux for a bit of the row output

endmodule

2-1 Mux module:

module mux2(input logic [1:0] data, select,
            output logic y);

    assign y = select ? data[1] : data[0];
endmodule

Best Answer

The SystemVerilog generate statements are elaborated at compile time, they are not procedural code. That means they are processed much like a macro or `ifdef statement, except that they can evaluate parameters, understand scope, and create new scopes. You need to get rid of the always_comb construct. The if/else if/else is also a generated block that produces only one row instance per iteration. Assuming n=8, then you will get three generated for-loop blocks named label[0], label[1], and label[2]. Your code get elaborated as if you could have written something like the following(assuming n gets overridden to 16.:

module barrel
    #(parameter n = 8; parameter control = $clog2(n))
    (input logic[n-1:0] data, input logic [control-1:0] select,
    output logic [n-1:0] result);

            logic [n-1:0] logic[0].tempResult;
            logic [n-1:0] logic[1].tempResult;
            logic [n-1:0] logic[2].tempResult;
            row #(n,1) logic[0].shiftLevel(
                    data,select[0],label[0].tempResult);
            row #(n,2) label[1].shiftLevel(
                    label[0].tempResult,select[1],label[1].tempResult);
            row #(n,4) label[1].shiftLevel(
                    label[1].tempResult,select[2],label[2].tempResult);
            row #(n,8) label[3].shiftLevel(
                    label[2].tempResult,select[3],result);
endmodule

Note that you could not declare identifiers (the variable names or the module instance names) with the label[x]. prefix without using the generate block construct.