Hi Folks,
This is a longish read. I am covering reg and integer keywords of Verilog. These two topics are quite huge, but I have summarized the most used ways here. I suggest that you type and practice to ascertain yourselves as you read. If you have any questions, put them below in the comment and we will address it.
Happy reading,
Handling ‘reg’ types in Verilog
One of the ‘reg’ types in Verilog is the ‘integer’. If you understand handling integers, the same principle can be applied to all reg types. A list of reg types in Verilog is given below for a quick ref:
This paper focuses more on the first 2 types. I will write another blog about the last three.
Integers in Verilog can be sized or unsized, and they are 4-state variables. The default size of a Verilog integer is 32 bits. An example of a sized integer value is 8’d10. An example of unsized integer value is ‘hF44.
Verilog allows you to specify the value in any of the supported radices — decimal, binary, octal or hexadecimal. Typical integer operations in Verilog are –
- Assignment of an integral value to an integer variable
- Assignment of an integer variable to another integer variable
Let’s consider these two use-cases first and then explore further. Let’s start with an example –
integer i;
i = 1;
In Verilog, if you do not specify the radix, it is assumed that you are talking in decimal. In the above example, we are assigning the value of decimal 1 to an integer which is 32 bits size. This value is stored in the Verilog run-time kernel in 32-bit format. The stored value is –
0000_0000_0000_0000_0000_0000_0000_0001
Let’s see some more examples to understand how absolute values could be stored in memory –
It does not matter how you use this value; it does not matter in what radix you specify the value; the storage is always like the above. In fact, irrespective of how the simulator implementation handles this storage, it is better to understand it exactly like how it is shown in the table above.
Let’s look at a very simple usage of such an integer through some examples –
integer i;
i = 10;
$display (“Value of i in decimal is %0d”, i);
$display (“Value of i in hexa-decimal is %x”, i);
You will notice that ‘i’ can be printed in any of the formats as desired. But, does that change the mechanism in which the absolute value of i is stored in the memory? No! So, the first thing to understand is that irrespective of the radix into which the value is cast (while using the value or variable), the value is referred to as an absolute value like shown above.
Another form of usage is like this –
integer i; reg [3:0] r;
r = 10;
i = r;
$display (“Value of i is %b”, i);
Here, we have a 4-bit value on the RHS and it is assigned to a 32-bit variable. If you run this code, the value of i printed on the console is 00000000000000000000000000001010. Why is that?
When a vector of smaller bit-width is assigned to a vector of a larger bit-width, the simulator does the following steps (assuming block assignment as in the above code):
- The RHS is evaluated. Here, the RHS value is 4-bit binary 1010 (as described in the storage method above)
- The size of LHS and RHS is compared. In our example above, the LHS bit-width is larger.
- If the bit-width is larger, the absolute value of RHS is padded with enough bits to make it equal to the bit-width of LHS. In this example, the value of 4-bit binary 1010 has to be padded with 28 additional MS bits
- Such padded bits have to be assigned a value which would NOT affect our original absolute value. Hence, the padded final value is 00000000000000000000000000001010
- This newly derived value (which is exactly equal to the original value) is assigned to the LHS
The scenario is no different if you just did
i = 4’d10;
Want to give it a try?
What happens if you try something quirky here? Let’s check the code below –
integer i; reg [3:0] r;
i = 32’bx110;
$display (“Value of i is %b”, i);
Guess the output? I have pasted it below for you –
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx110
How do we reason this? The Verilog specification says: if a bit vector has to be padded towards most-significant side, the padding rules are as follows –
- If the MS bit of the vector to be extended has a value of logic 1 or logic 0, the newly padded bits will carry a value of logic 0
- If the MS bit of the vector to be extended has a value of x or z, the newly padded bits will carry a value of x or z respectively
What this means is — if a <value> has to be left-extended, the value of the extension bits depends on the most-significant bit of <value>. If the most-significant bit of <value> carries a 1 or a 0, the <value> is left-extended with zeroes. In fact, it is absolutely correct way to handle the situation. If you want to keep the <value> un-altered, you have to put zeroes on the left.
Other than this, the other case is where the most-significant bit carries a 1’bx. In this scenario, Verilog specifies that you should assign the value of x to all left-extended bits. Similarly for cases of MS bit having the value of z, the newly padded bits will carry z.
If you understand this right, there is nothing new to be learnt with respect to assigning narrow vectors to wider vectors. The case where a wider vector is assigned to narrow vector, the extra most significant bits of RHS are truncated. It does not require much explanation.
A side-track
Ever wondered how a Verilog simulator models a 4-state value? If you open a the PLI header file (name and location of this file is specific to the simulator), you will find a definition like this:
/* data structure of vector values */
typedef struct t_vecval
{
int avalbits; /* bit-coding for each bit of vector: */
int bvalbits; /* ab: 00=0, 10=1, 11=X, 01=Z */
} s_vecval, *p_vecval;
If you do not know where to find it, just grep for t_vecval in the simulator install folder, you will find the file.
This is the data structure which returns the 4-state logic values of each bit in the Verilog simulator kernel. Of course, we do not have attributes of strength etc in this yet. It just stores the value. When you use PLI TF routines to exchange data between the Verilog and the C/C++ world, you will use this struct to accomplish the goal. The purpose of this paper is not to discuss PLI or data exchange, but I just thought it is helpful to know this. Happy learning, folks!
Tech Pubs,