Sunday, November 30, 2008

System Veriog GOTHCA 01

Types defined in different scopes:

The LRM words this as follows: ―The scope of a data type identifier shall include the hierarchical instance scope. In other words, each instance with a user-defined type declared inside the instance creates a unique type. To have type matching or equivalence among multiple instances of the same module, interface, or program, a class, enum, unpacked structure, or unpacked union type must be declared at a higher level in the compilation-unit scope than the declaration of the module, interface, or program, or imported from a package.

This has several implications. For example,

typedef struct {int A; int B;} AB_t;
typedef struct {int A; int B;} otherAB_t;

defines two different types and you cannot simply assign a variable of one type to a variable of the other, even though the type contents are identical. You must use an explicit type cast. GOTCHA!

Furthermore, if the type declaration of AB_t is found in module m, and m is instantiated twice, as m1 and m2, then the two types m1.AB_t and m2.AB_t are considered different types and again cannot be assigned from one to the other without an explicit cast.

However, if the typedef is found at a higher level, such as in the compilation-unit scope of the module ($unit), or in a package that is imported into the module, then the two module instances are considered to have the same type definition.

An anonymous type declaration also defines its own type. An anonymous type declaration is where the type definition appears as part of the variable declaration, and not as a separate typedef. For example:

struct {bit[15:0] value;} AB4, AB5;
struct {bit[15:0] value;} AB6;

AB4 and AB5 are defined with the same anonymous type declaration, and so they are assignment-compatible, but AB6 has a separate anonymous type definition and thus is not assignment-compatible with AB4 and AB5 without a cast, even though the type definitions are identical.

As stated in the LRM, these restrictions apply to enums, unpacked structures and unions, and classes. So they do not apply, for example, to packed structs or to arrays, packed or unpacked.

So a function can return an unpacked struct, for example, but you won‘t want to define the struct as an anonymous type in the function header, like this:

function struct {bit[15:0] value;} f(args);

because then you will not be able to assign the function return value to another variable in the calling scope, as they will be considered to have different types:

AB4 = f(args); // illegal, different types

Verilog Gotcha 02

Most of us have gotten used to the idea that numerical operands in an expression are size-extended to the size of the widest operand. We are less used to it with respect to strings, and it can hit us when we least expect it.

One particular case where it is easy to forget size-extension is in the conditional operator. If we write

cond ? expr1 : expr2

then the shorter expression of expr1 and expr2 is extended to the size of the wider one. But suppose we have something like this:

integer file; file = $fopen({"filename", dat1 ? ".dat1" : ".dat"}) ;

In this contrived example, we concatenate a file extension .dat1 or .dat to the given filename, where a variable called dat1 tells us the type of the file. If the variable dat1 is true, there is no problem, we open a file named ―filename.dat1‖, but if dat1 is false, then we try to open a file called ―filename .dat‖, with a space before ―.dat‖, which is extended to the size of ―.dat1‖ before being concatenated to ―filename‖. GOTCHA!

Actually, the shorter string literal is not extended with a space character, which is x20 ASCII, but rather with zeroes (zero-extension), which are null characters.

However, when used as a string, this often becomes a space. Note that if we had assigned the concatenation to a variable of string type, this would not occur.

string temp;
temp = {"filename", dat1 ? ".dat1" : ".dat"} ;
file = $fopen(temp) ;

The shorter string literal would still be zero-extended. However, upon assignment to string variables, null-characters are ignored, so ―.dat‖ would still be appended directly to ―filename‖.

Friday, November 7, 2008

Verilog Gotcha 01

What is a gotcha?

A gotcha is code that looks right, feels right, and smells right ... but isn‘t. If you‘re lucky, it won‘t pass compilation, so that you‘ll know immediately that something is wrong. If you‘re less lucky, it will do something obviously wrong in simulation, like getting stuck in reset. If you‘re really unlucky, it will pass compilation and simulate, but with a subtle error that you‘ll be hard pressed to detect. And in the worst case, it will cause a bug in silicon

GOTCHA Number-01:
This gotcha is already appear in Verilog (1995 or 2001) and are still in SystemVerilog :-)

always @* oscillations (V2K1)
For coding synthesizable RTL in Verilog-2001, we usually recommend to code combinational and latch blocks with always @* and its automatic sensitivity list instead of manually enumerating the sensitivity list in a regular always procedure.

However, there is a case where that can get you into trouble.
Suppose you have two always @* procedures containing for-loops and you use the same loop index variable for both, like this:

integer k; reg [31:0] out1[0:7], out2[0:15], in1, in2;
always @* for (k = 0; k <8; k = k+1) out1[k] = in1 + k ; always @* for (k = 0; k <16; k = k+1) out2[k] = in2 * k ; Why not? In Verilog-1995, we used the same loop index with multiple loops all the time for RTL without problems. Suddenly, in V2K1 (Verilog2001), they find that some simulators get stucked. All they did was change the sensitivity list to @*. Darn those language developers! Can‘t they leave well enough alone?? :-) What happens here is that according to the LRM of V2K1, the first always @* turns into "always @(in1 or k)" and the second turns into "always @(in2 or k)". Note that k appears in both lists. Suppose that in1 changes. This triggers the first always @* procedure. It executes, including the loop, and k changes a number of times. k changes, you said? That triggers the second procedure, even though in2 has not changed. The second procedure executes unnecessarily, wasting simulator time, but that is not the worst of it. When the second procedure executes, it also executes its for-loop, also changing k. This retriggers the first procedure. And so they go on, back and forth, with the simulator stuck in an infinite loop. GOTCHA! Why did this not happen in Verilog-1995? Because then we did not put the loop index into the manual sensitivity list. But in always @*, it is put in automatically. (This problem does not occur with all simulators. Apparently some of them don‘t put the loop index into the sensitivity list even though strict compliance to the LRM would do so.) How can we fix this ? (Solution to avoide this gotcha): Solution 01: We have to use different variables for each of the loops. We can declare two different variables globally, like this: integer k1, k2; reg [31:0] out1[0:7], out2[0:15], in1, in2; always @* for (k1 = 0; k1 <>out1[k1] = in1 + k1 ;

always @* for (k2 = 0; k2 <>out2[k2] = in2 * k2 ;

Solution 02 :
Another way is to declare the loop variables locally within the always @* procedures, like this:

reg [31:0] out1[0:7], out2[0:15], in1, in2;
always @*
begin:loop1
integer k;
for (k = 0; k < k =8; k= k+1) out1[k] = in1 + k ; end always @* begin:loop2 integer k; for (k = 0; k < 16; k = k+1) out2[k] = in2 * k ; end Solution if you are using SystemVerilog: If we can use SystemVerilog, then we can change the always @* to always_comb, which will not put in the sensitivity list any variable that is written to within the procedure. Another solution in SystemVerilog is to declare the loop variables within the for-statement itself, like this: for (int k = 0; k <>

This also makes each loop variable separate. This is the best solution, as using the same variable for the different loops is what caused the problem in the first place.

"Gotcha number 01 was over here, hope you have got the idea on this gotcha and now onwards keep in mind while coding"

Please feel free to discusse this gothcha if you have any question or doubt on ankitgopani83@gmail.com