Verilog parameterized one-hot encoder - logic

I'm a bit embarrassed as I thought this would be easy to write.
A fixed-width one-hot encoder would be easy to write with a case statement. But I'm wracking my brain trying to write a parameterized N-bit one-hot encoder. So far, I have:
module onehot_enc #(
parameter WIDTH
) (
input logic [WIDTH-1:0] in,
input logic [$clog2(WIDTH-1:0] out
);
genvar i;
generate
for(i = 0; i < WIDTH; i++) begin
assign out |= in[i] ? i : 0;
end
endgenerate
endmodule
But apparently "|=" is not an operator.
Anyone have any suggestions on writing this? It seemed so simple to do in my head...

You definitely need a loop for it. No generate block should be used here. The encider can be implemented within an always block.
Because you used 'logic' in your example, I assumed that system verilog syntax is ok here. So, please add the 'system verilog' tag.
In the following example the loop runs through the whole set of iterations without any 'break' to make it synthesizable. So, in this case the last '1' wins. The first out=0 statement assigns the default value of '0' to 'out'. It also makes the code combinational. Otherwise it would be a latch.
module onehot_enc #(
parameter WIDTH = 1
) (
input logic [WIDTH-1:0] in,
output logic [$clog2(WIDTH)-1:0] out
);
always_comb begin
out = 0;
for (int i = 0; i < WIDTH; i++) begin
if (in[i])
out = i;
end
end
endmodule

This only works if your one-hot is truly one-hot, but it doesn't try to priorty-encode the inputs, so it synthesizes smaller.
// one-hot to binary encode
function binary_type_t to_binary_f(vector_type_t v);
to_binary_f = '0;
for (int i=0; i<$bits(binary_type_t); i++) begin
for (int j=0; j<$bits(vector_type_t); j++) to_binary_f[i] |= (j%(2**(i+1)) >= 2**i) ? v[j] : '0;
end
endfunction

Related

For Loop In Verilog Does Not Converge

I'm attempting to using a for loop to count the repeated leading bit in a 32-bit number. For this, I am doing:
input[31:0] A;
output reg result;
Integer i;
for (i = 31; i > -1; i = i - 1) begin
if (A[i] == 0) begin
result = result + 1;
end
else if (A[i] == 1) begin
i = -1;
end
end
However, when I synthesize the program, I receive a warning saying that the program does not converge. Am I using the for loop wrong? Before this I used i >= 0 and even used a while instead but it doesn't change the outcome. I would appreciate any help. Should I set result to 0 before running the loop?
A[i] == 1 makes number of iterations non-deterministic and causes synthesis to fail. The way around it is letting the loop to unroll till the end and use a conditional variable to handle your calculations. Something like the following:
input[31:0] A;
output reg result;
Integer i;
reg flag;
flag = 0;
for (i = 31; i > -1; i = i - 1) begin
if (flag == 0 && A[i] == 0) begin
result = result + 1;
end
else if (A[i] == 1) begin
flag = 1;
end
end
I assume that it was some type of a flop logic, since in any case this would produce state elements. So, you need to use correct nbas for result and flag.
For synthesis for loops must converge during COMPILE time. Your condition of A[i]==1 can not be determined at compile time so the loops goes from 32 to 2^31-1 before it ends.
Verilog is an HDL, which in many aspects is totally different from standard computer languages.

Find the Maximum of an input vector in verilog

Im trying to get the maximum of an input vector. Im assuming all inputs are unsigned and that it should work on a range of bitwidths and array lengths.
I have to keep the parameters and input and output logic the way they are. Here is what I have, but I get a syntax error at the if statement:
module max
#(parameter int bW=16,
parameter int eC=8)
(input logic [bW-1:0] a[eC-1:0],
output logic [bW-1:0] z);
logic i=0;
always #* begin
for (i=0; i<size; i++) {
if(a[i] >z)
z = a[i];
}
end
endmodule
Maybe using a case statement would be better? I dont know. Any help would be nice!
Two simple problems.
You used brackets {/} instead of begin/end to wrap your looping statement. No need to wrap a single statement anyways.
You defined i as a single bit. use an int.
You'll also want to use a default for the initial value, then compute max from there.
For example:
module max
#(parameter int bW=16,
parameter int eC=8)
(input logic [bW-1:0] a[eC-1:0],
output logic [bW-1:0] z);
always #(*) begin
// defaults
z = 0;
for (int i=0; i<size; i++) begin
if (a[i] > z)
z = a[i];
end
end
endmodule
In addition to the other comments, I believe the for comparison value should be 'eC', not 'size'. This compiles for me (with the sverilog flag of course):
module max #(
parameter int bW = 16,
parameter int eC = 8
)
(
input logic [bW-1:0] a [eC-1:0],
output logic [bW-1:0] z
);
always #* begin
z = a[0];
for (int i=1; i<eC; i++) begin
if(a[i] > z) begin
z = a[i];
end
end
end
endmodule

Verilog - Why I can't declare multiple vars in a for statement?

I have a code like this:
generate
genvar i, j, k;
for (i = 0, j = 8, k = 0; i < 4; i = i + 1, j = j + 8, k = k + 8)
Register Register_inst (.d(w_data), .en(decoder_out[i]), .clk(clk), .q(trunc_32_to_n_bits(reg_out, j-1, k)));
endgenerate
Is it possible to have multiple vars in a for like in other languages?
There are two types of for-loops in Verilog, procedural for-loops (inside a initial or always block)and generate for-loops (outside of the initial and always block). Both are restricted to simple single variable assignments.
Typically you do not need multiple variables managed by a for-loop. In the majority of cases other values can be derived from one index. You code does not need three variables as everything can be determined from i:
generate
genvar i;
for (i = 0; i < 4; i = i + 1)
Register Register_inst (.d(w_data), .en(decoder_out[i]), .clk(clk), .q(reg_out[i*8 +: 8));
endgenerate
For more on the +: array slicing operatior, refer to earlier answered questions:
Indexing vectors and arrays with +: and What is `+:` and `-:`?
Note: SystemVerilog supports multiple variable assignments with procedural for-loops. There is still single variable assignment restriction with generate for-loops as per IEEE Std 1800-2012.

unpacking a vector into an array in verilog using for loops

Problem: I have N elements of X bits each, and have them concatenated into 1 vector and now I want to unpack them into a matrix M[N][X] using for loops. For example,
input [N*X-1:0]VECTOR;
integer i;
reg [X-1:0]M[N-1:0];
always#(*) begin
for(i=0; i<N; i=i+1) begin
M[i] = VECTOR[(X*(i+1)-1):(X*i)];
end
end
However, the above code gives me the following error:
Error (10734): Verilog HDL error at FILE.v(line_number): i is not a
constant
A few corrections:
input [N*X-1:0] VECTOR; // move range to the other side
integer i;
reg [X-1:0] M [0:N-1]; // Give proper range with X
always #* begin // always block for comb logic
for(i=0; i<N; i=i+1) begin // not i=i++
M[i] = VECTOR[X*i +: X]; // vector slicing
end
end
Refer to previously answered questions to explain +: vector slicing:
Indexing vectors and arrays with +:
What is +: and -:?

warning: suggest parentheses around assignment used as truth value in for loop

I am working on a program, but am having trouble with a for loop
for (int i = N-1; i = 0; i--) {
guessarray [i] = guess % 10;
guess /= 10;
}//for
With my g++ compiler I keep getting the error "warning: suggest parentheses around assignment used as truth value. I understand that I am working backwards in the loop, from low to high, but I don't see how that could be a problem. I have tried putting in parentheses in different places, but it doesn't work. I also know it has nothing to do with the assignment operator since I want to use the assignment operator. The warning is placed directly after N-1.
The compiler is simply calling your attention to the assignment in the for loop. It is probably doing so because the "for" statement has 3 semicolon-delimited expressions which is rather dense and prone to human error. By changing
for (int i = N-1; i = 0; i--)
to
for (int i = (N-1); i = 0; i--)
you are telling the compiler, that yes you really intended the for the initial value of i to be (N-1).
==================
Note also that there is what appears to be a logic flaw in the condition section of the for loop (the 2nd expresses ion)
You have
i = 0;
which means the loop will never execute (unless N==1). I assume your intent was to count down from (N-1) to 0. Thus You should probably have the following:
for (int i = (N-1); i >= 0; i--) // note the i >= 0 condition

Resources