SystemVerilog: unbased unsized literal in Concatenation - verilog

I assume that when placing an unbased, unsized literal on the left-most side of a concatenation will simply fill in any missing bits with the given value. I didn't see anything explicitly stating this in the LRM.
logic [63:0] rd_data;
logic [31:0] mem_dout;
logic [15:0] op_data;
....
assign rd_data = {'0, op_data, mem_dout};
Obviously, the following would be illegal:
Edit: As #dave_59 pointed out, this is legal, just not intuitive.
assign rd_data = {op_data, mem_dout, '0};
Just wanted to check if anyone knows that (1) this simulates as expected, and (2) the major synthesis tools do the correct thing and tie the upper 16 bits to 0.

Actually, both statements are legal. In a self-determined context '0 is equivalent to 1'b0. All the operands of a concatenation evaluate in a self-determined context. The result of both concatenations is a 32+16+1=49-bit expression. In the context of the assignment to rd_data, those expressions get right-aligned, and then left padded with 15 zeros.
So you get the result you are expecting, but for an entirely different reason.

Related

How to assign "all the last bits" automatically in Verilog

Consider this
reg [5:0]assign_me;
reg [11:0]source_of_data;
assign_me <= source_of_data[5:0];
where assign_me always gets the least significant bits of source_of_data. Here the 5 is hardcoded in the last line in the sense that if for some reason the definition of assign_me changes to reg [6:0]assign_me I will have to change the last line. Is there any way to avoid this? Like for example in a pythonic notation something like assign_me <= source_of_data[:0]?
You could use:
assign_me <= source_of_data;
Verilog will assign the LSB's. But, you might get warnings about width mismatch.
A cleaner way is to use a parameter:
parameter WIDTH = 6;
reg [WIDTH-1:0]assign_me;
reg [11:0]source_of_data;
assign_me <= source_of_data[WIDTH-1:0];
When it comes to integral (packed) arrays, Verilog is loosely typed. Verilog will right justify to align LSBs, then make the assignment padding or truncating the MSB. You do not need to select a specific set of bits unless you need to mask bits on either end. Some tools will generate size mismatch warnings, especially around port connections, but the language does not require it.
One thing to be careful of is that selecting bits of a single is always unsigned regardless of the sightedness of the signal as a whole.

Lint is unable to catch RHS and LSH width mismatch

Below piece of logic is doing 2^(3+x), where x is 2 bit value and can have max 2'b11, according to the below logic, RHS will be 1 << 6, which is 7'b1000000. MSB will be discarded as LHS is of 6 bits.
Checked this code in Spyglass Lint, VCS compile elab, Synthesis results etc, couldn't find any violation. Is there a tool that can find mistakes like below?
module module_test (
input wire [1:0] x,
output wire [5:0] y
);
assign y = 6’d1 << (3 + x);
endmodule
The problem is discarding some or all the bits of a value when shifting is a perfectly valid thing to want to do. A static linting tool checker is not designed to catch all possible functional bugs.
If you had an assertion that y must always have a one-hot value, then a formal property checker can statically determine that the result could be 0 and generate a violation. Assertions are what you use to capture design intent, and either a static formal tool or dynamic simulation tool can catch differences between intent and what got implemented in RTL.

What does this {} means after parameter in verilog?

module test #(parameter WIDTH = 4) (output wire [WIDTH-1:0] result, input wire input );
// synopsys template
assign result = {WIDTH{input}};
endmodule
In this code, {input} after WIDTH means what? In what way that affects the parameter?
The curly brackets, preceded by the parameter, are called the replication operator.
assign result = {WIDTH{input}};
makes WIDTH copies of the 1-bit input-signal and assigns it to the WIDTH-bit output signal result. This means that input does thus not affect the parameter like you suspected in your question. Rather, the parameter affects how many copies of input are made.
For future reference please also consult the SystemVerilog LRM. Simple syntax-related questions like yours can be easily looked up in that document. For example, take a look at Section 11.4.12.1 Replication operation in the document that I referenced.

creating a constant vector of variable width in verilog

I'm writing some synthesizable Verilog. I need to create a value to use as a mask in a larger expression. This value is a sequence of 1's, when the length is stored in some register:
buffer & {offset{1'h1}};
where buffer and offset are both registers. What I expect is for buffer to be anded with 11111... of width offset. However, the compiler says this illegal in verilog, since offset needs to be constant.
Instead, I wrote the following:
buffer & ~({WIDTH{1'h1}} << offset)
where WIDTH is a constant. This works. Both expressions are equivalent in terms of values, but obviously not in terms of the hardware that would be synthesized.
What's the difference?
The difference is because of the rules for context-determined expressions (detailed in sections 11.6 and 11.8 of the IEEE 1800-2017 LRM) require the width of all operands of an expression be known at compile time.
Your example is too simple to show where the complication arises, but let's say buffer was 16-bit signed variable. To perform bitwise-and (&), you first need to know size of both operands, then extend the smaller operand to match the size of the larger operand. If we don't know what the size of {offset{1'h1}} is, we don't know whether it needs to 0-extended, or buffer needs to be sign-extended.
Of course, the language could be defined to allow this so it works, but synthesis tools would be creating a lot of unnecessary additional hardware. And if we start applying this to more complex expressions, trying to determine how the bit-widths propagate becomes unmanageable.
Both parts of your question impliy the replication operator. The operator requires you to use a replication constant to show how many times to replicate. So, the first part of your example is illegal. The offset must be a constant, not a reg.
Also, the constant is not a width of something, but a number of times the {1} is repeated. So, the second part of the example is correct syntactically.

Verilog: bit slice vector twice

Suppose we have a 128 bit reg:
reg [127:0] line;
And we first select a 32-bit word out of it, and then select byte from this word, all using slicing:
word = line[(127-32*byte_addr[3:2])-:32];
byte = word[7:0];
That works fine. But if I wan't to combine both operators, in same line, it seems it is not permitted.
mybyte = line[(127-32*byte_addr[3:2])-:32][7:0]; //all the hell breaks loose
Unfortunately I couldn't find a clear rule in SV 3.1a spec that forbids this.
Please delete your SystemVerilog 3.1a spec and get a free copy of the 1800-2012 LRM
The concatenation operator described in section 11.4.12 does what you want.
mybyte = {line[(127-32*byte_addr[3:2])-:32]}[7:0];
The 1800-2012 LRM says (7.4.6)
An expression can select part of a packed array, or any integer type,
which is assumed to be numbered down to 0.
The term part-select refers
to a selection of one or more contiguous bits of a single-dimension
packed array.
No mention of a part-select of a part-select, which is what you are trying to do.
Can you make line multidimensional? Something like
reg [3:0][7:0] line [3:0];
This would make the indexing trivial.

Resources