How to have a binary number with constant lenght - verilog

I'm trying to write a test_bench for a dynamic size register.
I defined a parameter variable like this and instantiated a register module:
parameter integer regSize = 8;
register #(.size(regSize)) R1 (
.clock(clk),
.reset(rst),
.enable(enb),
.regIn(in),
.regOut(outp)
);
now forexample I want to define "in" variable ( the 4th input of module )
reg [regSize - 1: 0] in = (regSize)'b0;
I expect this works as : reg [regSize - 1: 0] in = 8'b0;
But it doesn't.
I get this error:
near "'b": syntax error, unexpected BASE, expecting ';' or ','
How should I write this?
Thanks for any help.

Use the concatenation repeat structure:
reg [regSize - 1: 0] in = {regSize{1'b0}};
Or in System Verilog you can do :
reg [regSize - 1: 0] in = '0;
You might also need something similar for adding e.g. 1 to a counter with variable length:
...
counter <= counter + {{(regSize-1){1'b0}},1'b1}; // regSize>1!
As that becomes difficult to read I prefer to use a localparam :
localparam [regSize-1:0] value_1 = {{(regSize-1){1'b0}},1'b1}; // regSize>1!
...
counter <= counter + value_1;
Note that it can get rather messy if you also want to have a width of 1 bit as but I assume adding 1 to a 1 bit counter is likely to be a design error.

There is no need to pad 0's to a number in Verilog, it does that automatically for you. You can just do
reg [regSize - 1: 0] in = 0;

Related

how to fix this verilog part-select error: Illegal operand for constant expression

So I'm having a input called tx_empty, and 255 bits data, my code is :
assign lastIndex = (tx_eop)? (tx_empty + 3'd4)*8 : lastIndex_xq;
wire [255:0] tmp1 = tx_data_xq[(tx_empty - 5'd16)*8-1 : 0];
wire [255:0] tmp2 = tx_data_xq[255:lastIndex];
wire [255:0] tmp3 = tx_data_xq[lastIndex +: 7'd96];
tx_empty is the input signal of this module, and "lastIndex_xq" is just the output of the D register of lastIndex. I want to change the index value when tx_eop is high.
tmp3 works fine, I'm getting error like "Illegal operand for constant expression" for tmp1 and tmp2, I know tmp2 is wrong because I cannot have a variable on the right hand side of a : in a part select. But how about tmp1? I have to use this part-select logic, is there any other way to do it?
Thanks in adv
verilog does not allow you to use variable widths in part select. Width must always be a constant. In your case it is not, because of tx_emtpty and last_index.
However, you can use bit shifts, masks and loops to handle it. Something like the following.
reg [255:0] mask1, mask2;
reg [255:0] tmp1, tmp2;
always #* begin
// create mask of '1' of the required width
mask1 = (256'b1 << (tx_empty - 5'd16)*8) - 1;
tmp1 = tx_data_xq & mask1;
mask2 = ~((256'b1 << lastIndex) - 1);
tmp2 = (tx_data_xq & mask2) >> lastIndex;
end

How the for loop works in this case?

As title. I'm quite unsure how the for loop would help to count the number of 1's in the input.
always #(*)
begin
for ( int i= 0 ;i< 255 ;i++ )
out = out + in[i];
end
If my input is 1001, out = out + in[1001]. So how can it count the number of 1's in this case?
Thank you
Assuming your input in is defined something like input [254:0] in then you would never have in[1001] as in is indexed on i that goes from 0 to 254.
As long as out is at least 8 bits, this should calculate the number of 1s in the input though not very efficiently for hardware as it's describing a long chain of 1-bit adders starting from in[0] + out to in[254] + out where the output of the previous adder is fed into the next. There is also an error as you need to initialize out to 0 or your loop will run forever as the always block depends on both in and out in its current implementation.
The main problem with your code is it doesn't initialize out. Without resetting out to zero, any change to in will only increment out; potentially overflow and keep adding.
The question is tagged as Verilog, but it is using SystemVerilog syntax. There proper Verilog way of writing this code would be:
integer i; // 'int' is a SystemVerilog keyword
always #(*)
begin
out = 0; // <-- initialize to zero
for ( i = 0 ; i < 255 ; i=i+1 ) // Verilog doesn't allow decelerating 'i' here or '++'
out = out + in[i];
end
With SystemVerilog, it can be written as bellow. Modern Verilog simulations are SystemVerilog simulations. The preferred way to enable the feature is changing the file extension from .v to .sv
always_comb
begin
out = '0; // <-- fill with zeros
for ( int i = 0 ; i < 255 ; i++ ) // or: foreach(in[i])
out += in[i];
end

Clean way to truncate result of addition or subtraction

When I do addition or subtraction in Verilog, some compilers emit warning.
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
// warning example
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 11 to match size of target (10) File: xxx.sv Line: xxx
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 32 to match size of target (10) File: xxx.sv Line: xxx
I want to find clean way to remove these warnings. I tried two methods:
// method 1
b <= (a + 1)[9 : 0];
// method 2
logic [10 : 0] d;
d <= a + 1;
b <= d[9 : 0];
I thought the first method would compile, but it was invalid syntax in verilog.
Second method works, but it is too verbose and dirty.
Is there any other clean ways?
From IEEE Std 1364-2001.
Page 73:
Table 29—Bit lengths resulting from self-determined expressions:
Unsized constant number = Same as integer
Page 45:
NOTE Implementations may limit the maximum size of an integer variable, but they shall at least be 32 bits.
So the warnings you see come from trying to operate one unsized numeric constant (32 bits at least) with a sized variable (10 bits), so the synthesizer warns about the result may overflow.
So, just make sure all your operands have the same size:
Instead of:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
Do:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 10'd1;
c <= a - 10'd1;
end
1 id a 32-bit value. As a result the width of the expression is 32.
The way around is to use a sized value of '1', i.e.
b <= a + 1'b1;
c <= b - 1'b1;
This can potentially give you an 11-bit result. Carryon bit will be lost. At this point you can do some other tricks. I guess this is the most common one. Use a carry on bit.
logic con;
logic[9:0] a,b;
...
{con, a} <= b + 1'b1;
You can use a temp variable, as in your example.
In general, verilog standard does allow free truncation or extension of operand widths and no warning is required. Definitely in this case you can ignore the warning or turn it off. I have not seen simulators which would warn about it. Just certain rule in linting tools.
Use curley concatination braces
b <= {a + 1}[9 : 0];
or change the constant size (which defaults to 32-bits)
b <= a + 10'd1;

Unexpected behaviour using the ternary operator (Verilog)

In the following Verilog module, I'd like to understand why the blocking assignment using concatenation doesn't give the same result as the 2 commented out blocking assignments.
When I run the program on the FPGA, it gives the expected result with the 2 blocking assignments (the leds blink), but not with the blocking assignment using concatenation (the leds stay off).
Bonus points for answers pointing to the Verilog specification explaining what is at play here!
/* Every second, the set of leds that are lit will change */
module blinky(
input clk,
output [3:0] led
);
reg [3:0] count = 0;
reg [27:0] i = 0;
localparam [27:0] nTicksPerSecond = 100000000;
assign led = {count[3],count[2],count[1],count[0]};
always # (posedge(clk)) begin
// This works:
//count = i==nTicksPerSecond ? (count + 1) : count;
//i = i==nTicksPerSecond ? 0 : i+1;
// But this doesn't:
{count,i} = i==nTicksPerSecond ?
{count+1, 28'b0 } :
{count , i+1};
end
endmodule
PS: I use Vivado 2018.2
The reason is because the widths of count+1 and i+1 are both 32 bits. An unsized number is 32 bits wide (1800-2017 LRM section 5.7.1) and the width of the addition operator is the size of the largest operand (LRM section 11.6.1). To make your code work, add a proper size to your numeric literals
{count,i} = i==nTicksPerSecond ?
{count+4'd1, 28'b0 } :
{count , i+28'd1};
A simpler way to write this code is
always # (posedge clk)
if (i== nTicksPerSecond)
begin
count <= count + 1;
i <= 0;
end
else
begin
i <= i + 1;
end

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

Resources