Electrical – How tonsert values in 2d array in verilog

shift-registerverilog

I wrote a verilog code for Circular Shift register using a 2-d array, but can't seem to insert values in the array.
Here is my code

    module cir_shift_reg_v(
        input CLK,
        output reg [16:0] BYTE_OUT
    );

    reg [16:0] byteShiftReg[9:0] = {16'h0,16'h1,16'h2,16'h3,16'h4,16'h5,16'h6,16'h7,16'h8,16'h9};
    integer i,j;

    always @(posedge CLK)
    begin
        BYTE_OUT <= byteShiftReg[0]; 
        for (i=0;i<9;i=i+1)
            byteShiftReg[i] <= byteShiftReg[i+1];

        byteShiftReg[9] <= BYTE_OUT;    
    end
    endmodule

I am getting an error during simulation saying

    Constant value or constant expression must be used for initialization

Best Answer

This is an important thing to understand. Verilog is a hardware description language, which means that what you are doing is not writing code the accesses 2D arrays and such, you are writing code that describes what hardware is required. In something like C (a procedural language), initialising an array is something that is done at run time - the CPU copies the contents of the array from the program memory into RAM and can then use it. However here you don't have that step.

Furthermore, the syntax you are trying to use is something from C, not Verilog. In fact in Verilog, {} means concatenation. So in essence what you are doing is concatenating ten 16bit values into a single 160bit vector. You are then trying to assign it as the initialisation value to a RAM which is not the same size - how does a 1x160 vector fit into a 10x16bit memory?

Also note that your register is declared the wrong size - you say you want it 16bits, but you've made each one 17bits ([16:0] = 17b).

You have two options to consider.

Option 1

The first choice is to split things up a bit. Rather than trying to do everything in one go, consider what your hardware is doing. In essence what you have is not a RAM, but rather sixteen 10bit circular shift registers. They all work in sync with each other, yes, but they are effectively sixteen copies of the same hardware, so lets work with that. How do we make sixteen identical copies of something? Two options, make a module and instantiate it sixteen times, or more simply use something called a generate loop - it's basically a for loop that instantiates multiple copies of hardware. Lets use the second option.

parameter INITIAL_VALUE = {16'h0,16'h1,16'h2,16'h3,16'h4,16'h5,16'h6,16'h7,16'h8,16'h9}; //Concatenate our initial values into a single parameter.

genvar j; //This is our generate loop variable.
generate for (j = 0; j < 16; j=j+1) begin : shift_reg_loop //shift_reg_loop is just a name for the loop. It can be any valid HDL name.

    //Now we instantiate one 10bit circular shift register
    reg [9:0] byteShiftReg; //Just 1 bit of the 16.
    integer i;
    initial begin
        for (i=0;i<9;i=i+1) begin
            byteShiftReg[i] = INITIAL_VALUE[i*16+j]; //Initialise each bit with the correct value extracted from our initial value.
        end
    end

    always @ (posedge CLK) begin
        BYTE_OUT[j] <= byteShiftReg[0]; 
        for (i=0;i<9;i=i+1) begin
            byteShiftReg[i] <= byteShiftReg[i+1];
        end
        byteShiftReg[9] <= BYTE_OUT[j];    
    end

end endgenerate //end of for loop and generate statement.

Option 2

Having said all of the above, actually in your case you don't really need to split things up, but I wanted to present the option first to give you a sense of what is going on under the hood so to speak, and give you some useful info for future work.

We can actually use one of the things I introduced in the other example to initialise the memory directly, the so called initial block. This allows you to do various things "at the beginning". Remember how I said that for a C program initialising the array is done at run time. Well in Verilog it is possible to do something similar but at synthesis. In other words, we can initialise the array by telling the synthesizer what the default value for each register (power on value) will be.

For multidimensional groups of registers, like memories, we can define an initial block which can do very similar things to your always block. In this case for loops.

parameter initialValue = {16'h0,16'h1,16'h2,16'h3,16'h4,16'h5,16'h6,16'h7,16'h8,16'h9}; //This works because concatenation makes it a 160bit wide value.

reg [15:0] byteShiftReg[9:0];

initial begin
    for (i=0;i<9;i=i+1) begin
        //Extract each 16bit chunk in turn from the initial value parameter
        //and use that as the initial value for this part of the shift register.
        // Note the (9-i) bit is used because concatenation of the initial value places the first value in the most significant bits, and last value in the least significant bits.
        byteShiftReg = initialValue[((9-i)*16)+:16];
    end
end

integer i;

always @(posedge CLK)
begin
    BYTE_OUT <= byteShiftReg[0]; 
    for (i=0;i<9;i=i+1) begin
        byteShiftReg[i] <= byteShiftReg[i+1];
    end
    byteShiftReg[9] <= BYTE_OUT;    
end
endmodule