Convert vector into array - verilog

I have a vector like this
wire [N:0] Vector[M:0];
and I want to convert it into an array of size M*N. A pseudocode could be:
Array={Vector[M],Vector[M-1],Vector[M-2],...,Vector[0]}
So I want to concatenate the elements of the vector in an array.
I tried to do it using a loop, but when I try to simulate it gives a fatal error without description. Is there a simpler way of doing it? Thanks!!!

I guessing you tried something like this: Array[N*(index+1) : N*index ] = Vector[index]; in an always block. This will not work because Verilog requires both sides of the range to be constants (during simulation).
There are three Verilog approaches to get the desired assignment:
Bit assignment
Array slice assignment
Generate loop assignment
Bit assignment
In Verilog-95 (IEEE1364-1995), the only ways achieve this was bit assignments with a double for-loop:
Array[N*index_m+index_n] = Vector[index_m][index_n];
reg [M*N:0] Array;
integer index_m, index_n;
always #(Vector) begin // Verilog-95 style sensitivity list
for(index_m=0; index_m <= M; index_m = index_m + 1) begin
for(index_n=0; index_n <= N; index_n = index_n + 1) begin
Array[N*index_m+index_n] = Vector[index_m][index_n];
end
endgenerate
Array slice assignment
Another approach is vector slicing with +: (A feature added in IEEE1364-2001. Refer to Indexing vectors and arrays with +:). This allows one variable starting index and a constant offset for the range.
Array[N*index +: N ] = Vector[index];
reg [M*N:0] Array;
integer index;
always #* begin // Verilog-2001 style sensitivity list
for(index=0; index <= M; index = index + 1) begin
Array[index*N +: N ] = Vector[index];
end
endgenerate
Generate loop assignment
A third approach would be to use a generate block (also added in IEEE1364-2001). A generate blocks for-loop unravels at elaboration. There form you could use Array[N*(index+1) : N*index ] = Vector[index];, provided that index is a genvar:
Or with a generate block
wire [M*N:0] Array; // note 'wire'
generate
genvar g_index; // The 'g_' prefix is suggested coding style to identified genvars
for(g_index=0; g_index <= M; g_index = g_index + 1) begin
assign Array[(g_index+1)*N] : g_index*N] = Vector[g_index];
//assign Array[g_index*N +: N ] = Vector[g_index]; // +: also works
end
endgenerate
SytemVerilog (IEEE1800) added bit streaming which can do the operation in one step Array = {>>{Vector}};, but I am unaware how common it is supported for synthesis. (I typically use array slicing (+:) with SystemVerilog's foreach in an always_comb)

Related

How to dynamically change value assigned to a vector register

I am a newbie to verilog coding. In my problem statement, I will get number of entries in a sorted table from another module and based on number of entries I need to decide where should I start my binary search
(e.g. Let num_entries be 15, then start index should be 8). Code snippet is given below:
srch_addr <= {{(TBL_AW-msb_loc(num_entries)-1){1'b0}},2'b10, {(msb_loc(num_entries)-1){1'b0}}};
//function to find out MSB 1
integer LOC;
function [3:0] msb_loc;
input [TBL_AW:0] num_entries;
reg found;
//input start;
begin
//if(start = 1)
//begin
found = 1'b0;
msb_loc = 3'b000;
for (LOC=TBL_AW; LOC> 0; LOC=LOC-1)
begin
if((num_entries[LOC] == 1) && !found)
begin
msb_loc = LOC;
found = 1'b1; //TO exit the loop
end
end
//end
end
endfunction
Compiler gives me this error "Illegal operand for constant expression". What can be done to resolve this error?
The replicator 'count' value must be a non-zero, non-X and non-Z constant expression.
{(TBL_AW-msb_loc(num_entries)-1){1'b0}}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not a constant.
To get the 'halfway' address you can just the standard mathematical way: divided and round upwards. In this case add one and divide by two:
srch_addr <= (msb_loc(num_entries)+1)>>1;
Coming back to your formula. This part just makes zeros: {(TBL_AW-msb_loc(num_entries)-1){1'b0}} You don't need that.
This part 2'b10, {(msb_loc(num_entries)-1){1'b0}} actually shifts 2'b10 left by "(msb_loc(num_entries)-1)" positions.
This does the same but then without syntax errors:
srch_addr <= 1'b1 << msb_loc(num_entries);
What I can see it does NOT give you the half-way address.
Further:
Your integer LOC; should be inside your function as a local variable.

How to use the input's values in "always" definiton in Verilog

I got the problem with using the input's value in Verilog.
I write:
module reg_vector (INPUT, ICLK, IENBL, NR, OUT);
parameter k = 6;
parameter n = 3;
input [(8*k)-1:0] INPUT;
input ICLK;
input IENBL;
input [n-1:0] NR;
reg [n-1:0] temp;
output reg [7:0] OUT;
always# (temp, posedge ICLK)
begin
if (IENBL)
begin
OUT = INPUT[temp*8 : temp*8+8];
end
end
endmodule
But got the error:
Error (10734): Verilog HDL error at reg_vector.v(25): temp is not a
constant
How should I fix it?
Thank you)
INPUT[temp*8 : temp*8+8] does not work because the : range syntax requires both sides to be a constant.
What you want is to use the +: array slicing: INPUT[temp*8 +: 8]
The left hand side of +: allows variables and represents the starting index. The right hand side is the width and must be a constant. For more on +: see Indexing vectors and arrays with +:
Other issues:
Remove temp from the sensitivity list.
temp needs to be assigned to something
OUT should be assigned with non-blocking (<=) not blocking (=) since it is sequential logic.
always #(posedge ICLK) // no temp in sensitivity list
begin
if (IENBL)
begin
OUT <= INPUT[temp*8 +: 8]; // non-blocking and +:
end
end
Even if your vector is always 1 byte wide, the tool understands it as a variable size and it does not know how to deal with it. (you also inverted the indexes temp*8 and temp*8+8 in the vector selection)
Another way to do it is to use the shift operator
OUT = INPUT >> (temp*8);
This should work as OUT will take the lower 8bits of the shifting by 8*temp of INPUT

The left-hand-side of continuous assignment is illegal

My input consists of a parameterized number of units. The output I need is to remove the first bit of each unit.
For example if the input has units of size 3-bits each and the input value was 011011, the output should be 1111
Here is the solution i used for this:
parameter data_in_size = 11;
parameter data_out_size = 10;
parameter units = 4;
parameter skip_bits = 1;
input [data_in_size * units - 1 : 0] data_in;
output [data_in_size * units - 1 : 0] data_out;
genvar i;
generate
for (i = 0; i < units; i = i + 1) begin
assign data_out[data_out_size * i +: data_out_size] = data_in [(data_in_size * i + skip_bits) +: data_out_size];
end
endgenerate
But I get the following error The left-hand-side of continuous assignment is illegal
How can i get through this error and why i am getting it ?
Your code works perfectly well. Might be a simulator issue.
But I would like to focus on logic implementation in your code. The logic seems to be wrong.
First error seems to be in declaration of data_out and the slicing logic : data_in [(data_in_size * i + skip_bits) +: data_out_size] must be replaced with: data_in [(data_in_size * i + skip_bits) +: data_in_size]
Lets suppose i=0; data_out_size=3; data_in_size=4 then the LHS evaluates to data_out[2:0] = data_in[4:1]. When i=1, data_out[5:3] = data_in[8:5]. As you can see the bit slicing seems to be incorrect. Since LSB is sliced.
I think you might need to have following logic for bit slicing:
assign data_out[data_out_size * i +: data_out_size] = data_in[(data_in_size * i) +: (data_in_size - skip_bits)];
This will slice the MSB bit of every unit chunk, keeping the rest of bits as it is.
I simulated your code at EdaPlayground here. As an example, you will have following data_out and data_in values. Note the sliced MSB from each unit.
data_int = 1100101010010101
data_out = 100010001101

How to dynamically reverse the bit position in verilog?

wire [9:0] data_reg;
reg [3:0] Reverse_Count = 8; //This register is derived in logic and I need to use it in following logic in order to reverse the bit position.
assign data_reg[9:0] = 10'h88; // Data Register
genvar i;
for (i=0; i< Reverse_Count; i=i+1)
assign IReg_swiz[i] = IReg[Reverse_Count - 1 -i];
This is generating syntax error. May I know how to do this in verilog
If you'd have Reverse_Count as constant, your task boils down to just wire mix-up, which is essentially free in HDL.
In your case, the task can be nicely reduced to first mirroring wide data and then shifting by Reverse_Count to get LBS bit on its position, which itself is done just by a row of N-to-1 multiplexers.
integer i;
reg [9:0] reversed;
wire [9:0] result;
// mirror bits in wide 10-bit value
always #*
for(i=0;i<10;i=i+1)
reversed[i] = data_reg[9-i];
// settle LSB on its place
assign result = reversed>>(10-Reverse_Count);
Reverse_Count is not a constant, ie it is not a parameter or localparam.
This means that the generate statement you would be creating and destroying hardware as required, this is not allowed in verilog as it would not be possible in hardware.
The Bus that your reversing should have a fixed width at compile time, it should be possible to declare Reverse_Count as a parameter.
Since the value of Reverse_Count dunamic, you cannot use a generate statement. You can use an always block with for-loop. To be synthesizable, the for-loop needs able to static unroll. To decide which bits reverse, use an if condition to compare the indexing value and Reverse_Count
Example:
parameter MAX = 10;
reg [MAX-1:0] IReg_swiz;
integer i;
always #* begin
for (i=0; i < MAX ; i=i+1) begin
if (i < Reverse_Count) begin
IReg_swiz[i] = IReg[Reverse_Count - 1 -i];
end
else begin
// All bits need to be assigned or complex latching logic will be inferred.
IReg_swiz[i] = IReg[i]; // Other values okay depending on your requirements.
end
end
end

Calculating a parameter in a loop generate block

I have an array of parameters WIDTHS, and I need to calculate another parameter RIGHT based on some values in WIDTHS in a generate block. Is this possible? If not, is there an alternative way?
Here is an example of what I am trying to do. Suppose we have a predefined register module REG which has inputs d, q, we (write enable), CLK and _RESET. I would like to create a new module called GroupReg, which instantiates N instances of REG. Each instance has a different width (hence the WIDTH parameter array). The d, q, and we of each group are aggregated in arrays with the same name in GroupReg and need to be specified for each instance. Specifying we is easy (we[i]) since it is only one bit. However, specifying d and q with the correct LEFT and RIGHT values is where I have problem with since each group has a different width.
Looks like the only way to assign a value to a parameter is upon its definition, which prevents assigning a value to it in a generate loop.
module GroupReg(d, q, we, CLK, _RESET);
parameter N = 4; //Number of groups
//INDICES has to have N+1 members. Last member should be 0
parameter integer WIDTHS [N:0] = {40, 30, 20, 10, 0};
parameter integer DW_TOTAL = 128;
input logic [DW_TOTAL-1:0] d; // Data Input
input logic [N-1:0] we; // write enable
input logic CLK; // Clock Input
input logic _RESET; // Reset input (active low)
output logic [DW_TOTAL-1:0] q; // Q output
genvar i, j;
for (i=N-1 ; i>=0 ; i--) begin:REGISTERS
localparam WIDTH = WIDTHS[i];
localparam LEFT = RIGHT + WIDTHS[i];;
localparam RIGHT = 0;
for (j = 0 ; j<i ; j++) // <<----- Does not work
RIGHT = RIGHT + WIDTH[j];
REG #(
.DW (WIDTH),
)
reg_i
(
.d(d[LEFT:RIGHT]),
.q(q[LEFT:RIGHT]),
.we(we[i]),
.CLK(CLK),
._RESET(_RESET)
);
end : REGISTERS
endmodule
I tried using the sum() array reduction method on WIDTHS and it worked in Aldec Riviera PRO:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
parameter integer DW_TOTAL = WIDTHS.sum();
initial begin
$display("DW_TOTAL", DW_TOTAL);
end
endmodule
If you're lucky it's going to work in your simulator too.
I anyway don't really get what you're trying to do making N a parameter, seeing as how you're anyway hardcoding a fixed number of values for the widths.
This works in Modelsim:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
genvar i;
for (i=N-1 ; i>=0 ; i--) begin
localparam integer FOO[i:0] = WIDTHS[i:0];
//localparam RIGHT = FOO.sum();
initial begin
foreach (FOO[i])
$display("FOO[%0d] = %h", i, FOO[i]);
end
end
endmodule
The FOO parameter would only store the relevant entries from WIDTH for a specific loop iteration. If sum() would work, you'd be home free. The slicing syntax doesn't work in Riviera, however.
This is a typical example of vendors interpreting the standard differently, basically because it's not specific enough. Still, if you use a simulator from a different EDA company, try combining the two answers; maybe you're lucky and it works.

Resources