Just When You Thought It Was Safe to Start Coding Again ...

Return of the SystemVerilog Gotchas

Shalom Bresticker

Intel Corporation Shalom.Bresticker@intel.com
ABSTRACT All programming languages have gotchas: easy-to-make errors or misunderstandings that look OK, but don't work, don't behave as expected, or differ between tools. The canonical example from C is writing "if (a=b)" instead of "if (a==b)". Knowing about SystemVerilog's gotchas helps prevent making these mistakes, and eases detecting and debugging them when they do occur. Sutherland and Mills published a book of gotchas in 2007, but there are many more. This paper presents a selection of additional gotchas that have bitten the author and his colleagues over the years, some of them very nasty. The gotchas are divided into (1) gotchas that exist in Verilog (2) gotchas that are new in SystemVerilog (3) gotchas connected to how the RTL code is synthesized. This is a revision of a paper of the same name that was presented at Boston SNUG 2008. This work does not in any way constitute an Intel endorsement of a product or supplier.

Table of Contents
1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 4.0 4.1 4.2 4.3 4.4 4.5 4.6 5.0 6.0 7.0 Introduction ......................................................................................................................... 4 Abbreviations and terminology........................................................................................... 4 Why are there gotchas? ....................................................................................................... 5 What types of gotchas are there? ........................................................................................ 6 Where do gotchas come from? ........................................................................................... 7 How to deal with gotchas .................................................................................................... 8 Previous work ..................................................................................................................... 9 What follows in the rest of the paper .................................................................................. 9 Verilog Gotchas ................................................................................................................ 10 always @* oscillations (V2K1) .................................................................................... 10 always procedures that are never executed .................................................................... 12 Misuse of logical AND and OR ........................................................................................ 13 Zero replication constants ................................................................................................. 14 Negative replication constants .......................................................................................... 16 Elaboration of unused illegal parameterized code ............................................................ 16 Incorrectly written indexed part-select (V2K1) ................................................................ 17 String size-extension ......................................................................................................... 18 Macro expressions need to be in parentheses ................................................................... 19 Macro call within string literal .......................................................................................... 20 Null ports .......................................................................................................................... 21 SystemVerilog Gotchas..................................................................................................... 22 Types defined in different scopes ..................................................................................... 22 Arrays vs. queues .............................................................................................................. 23 Using `` for concatenation within an escaped identifier ................................................... 24 Use of special macro character sequences outside of macros ........................................... 25 Are spaces around macro arguments dropped? ................................................................. 26 String equality and compare functions have opposite return values ................................. 27 Glitches in unique/priority ..................................................................................... 27 Glitches in immediate assertions ...................................................................................... 28 Assignments in expressions .............................................................................................. 29 Uneven coverage bin distribution ..................................................................................... 30 const variables are not parameters ................................................................................. 31 The static initialization order fiasco .................................................................................. 32 Synthesis Gotchas ............................................................................................................. 33 always_comb does not guarantee combinational logic ................................................ 33 My flip-flop is a latch! ...................................................................................................... 34 Myth: default/full_case/unique/priority prevent latches........................ 36 Why is my combinational logic considered sequential? ................................................... 39 A synthesis engine is not as smart as a formal engine ...................................................... 39 Asynchronous reset loops in flip-flops ............................................................................. 41 Conclusions and Recommendations ................................................................................. 42 Acknowledgements ........................................................................................................... 43 References ......................................................................................................................... 43

SNUG Boston 2008

2

Return of the SystemVerilog Gotchas

8.0

About the Author .............................................................................................................. 44

SNUG Boston 2008

3

Return of the SystemVerilog Gotchas

1.0 Introduction
What can be said about Verilog and SystemVerilog gotchas that has not yet been said? Plenty, it turns out. That‘s bad for users and application engineers, but it‘s good for authors of papers. What is a gotcha? A gotcha is code that looks right, feels right, and smells right ... but isn‘t. (See [21] for a fuller definition.) 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. Two papers in recent SNUGs have described Verilog and SystemVerilog gotchas, by Stuart Sutherland and Don Mills (and Chris Spear on the second one). Stuart and Don followed this up with a book that took the two papers and revised them, as well as adding additional gotchas. This paper follows in their footsteps. The list of gotchas is not over yet, and even after this paper, we still have more. Gotchas come in various degrees of severity, but we will try to describe some of the nastier ones, which we or our colleagues have actually experienced. However, we will also show a few mild ones as well. The gotchas come from all versions of Verilog and SystemVerilog, so that both a person who is still using only Verilog-1995 and one who is writing in SystemVerilog can learn from this paper. In addition to gotchas in the language, we will also mention a few gotchas which derive purely from how various constructs are synthesized. This is a revised version of a paper of the same name that was presented at Boston SNUG 2008. Minor changes were made in various places, sections 2.11, 3.9-3.12, and 4.6 are new, and reference [22] was added. 1.1 Abbreviations and terminology We will be using the following abbreviations:         LRM - Language Reference Manual. Refers to the language standard documents. See the References section at the end of the paper for the exact references. V95 – Verilog-1995, IEEE Std 1364-1995, Reference [4]. V2K1 – Verilog-2001, IEEE Std 1364-2001, Reference [5]. V2K5 – Verilog-2005, IEEE Std 1364-2005, Reference [6]. SV – the SystemVerilog language, in a generic sense. SV-2005 - SystemVerilog-2005, IEEE Std 1800-2005, Reference [7]. SV-2009 - SystemVerilog-2009. The next revision of IEEE Std 1800, in progress, planned to be approved in 2009. WG – Working Group. Refers to the IEEE P1800 SystemVerilog standards committee.

SNUG Boston 2008

4

Return of the SystemVerilog Gotchas

Many users to refer to code segments that begin with "always" as "blocks", i.e., "always blocks". The IEEE SV WG has decided to call them consistently "procedures", and so that is the term we use in this paper. Mantis[35] is the issues database of the IEEE 1800 SV standards committee. Mantis is the name of an insect, i.e., a "bug", but the database contains clarification and enhancement requests as well as reports of errata in the standard. This paper references some Mantis items. Read access to the database is public. To get to an issue, you go to http://www.eda.org/svdb, and log in with Username and Password both ―guest‖. Then in the upper right hand corner, you enter the Issue # in the box that says ―Issue #‖ and press on ―Jump‖. That‘s it. (As shorthand, we often say simply "Mantis N" instead of "Mantis issue number N". I use "Manti" as a shorthand plural form instead of "Mantis issues".) 1.2 Why are there gotchas? Why do gotchas exist? I could give a few humorous answers, such as:    They give us something to write papers and books about. They give us an excuse why our design does not work and why we are late. They give job security for verification engineers.

But seriously, this is actually an important question, because sometimes people really ask why there have to be gotchas. So here are a few serious answers: ALL programming languages have gotchas. It is inherent in their nature. It does NOT mean that SV is a bad language, but it does mean that you need to be careful. There are some languages that have fewer gotchas. Generally, they are more verbose and less flexible and users don‘t like them (e.g., ADA). Such languages can be good for writing code for life-critical applications, like spacecraft. Also, SV is not just a programming language. It is a Hardware Description and Verification Language, making it much more than a general purpose programming language. SV is big (the LRM is over 1200 pages long) and complex. It is also still relatively new and still evolving. Like any other human endeavor, it is not perfect, just as the only programs without bugs are trivial ones. Such a document is difficult to verify completely and cannot be done automatically. It is also important to understand that most of the members of the standards committee work either as volunteers on their own time, or at best their employer allows them a limited amount of time to work on it. There are very few people, if any, whose main assignment from their employer is to work on the SV standard. Sometimes you hear comments that basically accuse the standards committee of making silly decisions. Sorry, I disagree. They sometimes make errors or bad decisions, like all humans, but the committee contains some of the top industry experts. Usually there was a good reason why the standard was defined in a certain way. In retrospect, it can sometimes turn out that it was not
SNUG Boston 2008 5 Return of the SystemVerilog Gotchas

always the best decision. There is also often a need to make compromise between multiple considerations. In my experience, inter-company politics is rarely a factor. Ambiguities can arise because the contributors to the standards committee are engineers, not technical writers. Sometimes, they write not in the best way. They may forget that readers of the LRM are not as expert in the language as they are. Sometimes they thought that what they wrote was clear or that a particular point was obvious, and maybe it is to most readers, and yet there may still be a significant minority of readers for whom it is not clear or obvious. Another problem is that the full description of all the information related to a particular construct is sometimes distributed over several places, or simply difficult to find. Additionally, the textual descriptions in the LRM are often informal. This is actually good, as it makes the LRM much more understandable than many others I have seen, but has the price sometimes of less preciseness. There is sometimes a tradeoff between clarity and preciseness. Finally, sometimes the committee knew there was an issue, but did not have time to handle it. With limited resources (manpower, time), priorities are often determined by importance and complexity. 1.3 What types of gotchas are there? There are different ways to classify gotchas. One way is by the symptoms it causes. For example:      You think it should compile/elaborate cleanly, but it doesn‘t. Either it fails completely or it gives an unexpected warning. It may compile, but behave differently than you expected. It may not work at all, such as producing X outputs, getting stuck in a loop, or not finishing reset. One of the most dangerous types of gotchas is where it behaves differently, but not blatantly. Then it is hard to spot that there is even a problem. Another difficult type of gotcha is where it fails intermittently. Then you also have to try to understand under what conditions it fails. A gotcha may express itself by working on some tools or tool versions and failing on others.

Another way to classify gotchas is whether they are written "accidentally" or "deliberately". By this, I mean the following:  An "accidentally" written gotcha is one where you write something different than what you really intended to write, due to a typographical error or due to forgetfulness, for example. If someone would point out to you what you wrote, you would say, "Oops!". This turns from a simple error into a gotcha if it is difficult to spot the mistake or if instead of completely failing, the code works but wrongly. A "deliberately" written gotcha is one where you wrote what you intended to write, because that is how you believe and understand it should be written, and you are unaware that your understanding is incorrect or that there is some problem with it. If someone would point out to you what you wrote, you would say, "So what? What is the problem?".

SNUG Boston 2008

6

Return of the SystemVerilog Gotchas

1.4 Where do gotchas come from? There are various sources of gotchas. We‘ll mention a few, but there are others. One of the classic gotcha forms is where there are two similar syntax forms that are both legal, but behave differently. You may get confused between them, or simply accidentally write the wrong one. Gotchas 2.3 and 2.7 below are of this type. A major source of gotchas is ambiguities in the LRM. There are cases that are unspecified. In some places, there is unclear or misleading language. Unspecified cases can occur because no one thought of them or because someone did think of them but thought that the LRM does specify the behavior in that case, and only deeper thought shows that it is not specified well enough. Gotcha 2.10 below is an example of this. Sometimes an ambiguity is deliberate because the committee was unable to reach a consensus on the desired behavior and just leaves the issue open. Gotcha 3.3 below is one that is still unresolved for this reason. Other times, though, users or developers misunderstand the LRM even though the LRM does explain it clearly. Someone may have a blind spot in reading that section of the LRM. Occasionally, people make an incorrect deduction because some statement that appears in one place is not repeated somewhere else, and then they (incorrectly) conclude that the statement does not apply in the second place. Among the worst problems is where tools implement an ambiguity differently. Then your code becomes non-portable. You may not even be aware of the problem and discover it at the worst possible time. Gotcha 3.4 below is a good example of this. Another source of gotchas is errors in the LRM. It is not so bad when the error is obvious. But when it is not so obvious, one tool may implement the LRM as written while another implements the ―correct‖ behavior. Similarly, one user may expect the tool to implement the LRM as written, whereas another may expect the tool to implement the ―correct‖ behavior. A mismatch between the user and the tool, moving the code from one tool to another, even one user reusing the code of another, may all result in unexpected behavior. Another problem is differences between versions of the language. You can get confused. The differences are almost not documented in the LRM itself. So what worked till now might not work or might not work the same way in the future, although the standards committee tries to minimize that. The biggest problem is usually new keywords, but occasionally there are other things, such as generate syntax and semantics that changed from V2K1 to V2K5. You especially have to be careful when writing code according to a newer version of the LRM, then moving to a tool that uses an older one. In fact, sometimes different tools from the same vendor implement different versions of the standard. And two versions of a tool may implement different versions of the LRM. Or a tool may implement some features according to one version

SNUG Boston 2008

7

Return of the SystemVerilog Gotchas

of the LRM and others according to another. In addition, of course, each tool implements a different subset of features of the LRM. It is also very difficult to obtain full and accurate documentation about what each tool implements and how it does so. (To be fair, the tool vendors have a tough job. Each version of the standard adds a bunch of new features and corrects errors in the previous versions. Vendors are always playing catch-up.) There are recognized gotchas that the committee would love to remove but is unable to do so, because that would break back-compatibility. Legacy code would stop working. A lot of SystemVerilog is based on older languages such as C and Vera. In some cases, SV implements features in the same way as the older language and sometimes differently. Where it is the same as the older language, it inherits gotchas from that language. Where it is different, there is a new gotcha: people expect it to be like the older language, but it is different. Some days, you just can't win! Built-in default behavior in the language can also be a gotcha source. What happens when you do not specify something explicitly in the code? If you are unaware of or forget the default behavior, you may get unexpected results. An example is how module port attributes, such as direction, kind (net or variable), and packed and unpacked dimensions, are inherited from previous ports in the port list. (This particular one is clarified in the next revision of the LRM, see Mantis 1465.) There are other sources of gotchas, but this paper is supposed to be about the gotchas themselves, not where they come from, so we'll stop here. 1.5 How to deal with gotchas What benefits do we have from knowing about all these gotchas? It can help us prevent them from occurring. Awareness causes more careful coding. You can formulate coding guidelines that reduce the risk of making these mistakes. Context-sensitive editors (e.g., with auto-indent) can aid us. Knowing about gotchas helps us to detect them after they have already been written. We can look for them in code reviews. We can have Lint tools check for them. When trying to debug a problem, they give us ideas of possible causes to look for, at least subconsciously. We can try to match the symptoms with possible causes. Experience also gives you an idea of the frequency with which gotchas occur. Just hearing the symptom often enables you to make a good guess of the problem. Since some gotchas come from ambiguities and errors in the LRMs and from the fact that the 2005 standard is comprised of a combination of the Verilog and SystemVerilog LRMs, it is helpful to look at an up-to-date draft of the new merged SystemVerilog LRM (if your company has access to it). Besides eliminating most of the confusion that resulted from having two

SNUG Boston 2008

8

Return of the SystemVerilog Gotchas

different LRMs, the new merged LRM also contains many corrections and clarifications to the 2005 standard. This makes it much clearer in many cases what the correct behavior is. Finally, consider participating in the IEEE P1800 SV standards committee. This brings you together with the top SV experts in the industry and brings to your attention issues that you would never otherwise hear about, often before you encounter them yourself. It also gives you a forum before which you can bring up issues for discussion. Of course, it is not for beginners, but you won‘t be a beginner any more after reading this paper! 1.6 Previous work Gotchas are as old as the Verilog language, of course (Older, actually, since some of them are inherited from earlier languages.). It's surprising, then, that only a couple of years ago, Stuart Sutherland and Don Mills had the brilliant idea of compiling Verilog and SystemVerilog gotchas in an orderly way, first in two SNUG papers ([1] and [2]) and then in a book based on those papers ([3]). At SNUG Israel 2007, Qualcomm engineers presented gotchas related to the Vera constraint solver [22]. Since that part of SystemVerilog was based on Vera, those gotchas are largely relevant to SystemVerilog as well. The same engineers are presenting more Vera gotchas at SNUG Israel 2009. Earlier, Don Mills and Cliff Cummings compiled some gotchas related to synthesis-simulation mismatches ([14]) and there were a number of papers that touched on various specific types of gotchas, particularly related to X-propagation (See [13] and [15]-[19], for example). Two excellent recent books devoted to teaching the design and verification parts of SystemVerilog ([9] and [10]) made a point of noting gotchas related to the new SystemVerilog features discussed. [11] is a very nice book written in Question and Answer fashion that also discusses a number of gotchas. Although the book title mentions only Verilog, it also discusses some SystemVerilog. Finally, the Doulos SV Reference Guide ([12]) is organized according to alphabetical order of language construct names. Many of the sections include, in addition to a description of the construct, "Tips" and "Gotchas!" related to the construct. Very nice. 1.7 What follows in the rest of the paper The rest of this paper describes a number of gotchas of various types. Section 2 describes gotchas that exist in older versions of Verilog (1995, 2001, 2005) as well as in SystemVerilog. Section 3 describes gotchas that are new in SystemVerilog. Section 4 describes gotchas that derive from how your RTL code is synthesized. Section 5 contains some closing words of encouragement and advice so that you won't finish reading this paper feeling that there is no hope of writing code that will actually work.

SNUG Boston 2008

9

Return of the SystemVerilog Gotchas

2.0 Verilog Gotchas
This section describes some gotchas that already appear in Verilog (1995 or 2001) and are still in SystemVerilog. 2.1 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. (Gotcha 66 in [3] does show a potential problem, but that rarely occurred in synthesizable RTL.) Suddenly, in V2K1, we find that some simulators get stuck. All we 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

SNUG Boston 2008

10

Return of the SystemVerilog Gotchas

list even though strict compliance to the LRM would do so.) This gotcha occurred in the ovl_arbiter logic of the OVL (Open Verification Library) as well. This only occurs when both loops are in always @* procedures. If only one loop is, and the other is in a sequential always @(posedge clk) procedure or a regular always procedure with a manual sensitivity list and the loop index does not appear in the list, then this will not happen. Workarounds: How can we fix this? One way is to avoid using always @* with loops, but we would like to avoid writing the sensitivity list manually. Within Verilog-2001, we have two workarounds. 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 < 8; k1 = k1 + 1) out1[k1] = in1 + k1 ; always @* for (k2 = 0; k2 < 16; k2 = k2 + 1) out2[k2] = in2 * k2 ; 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 < 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 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 (which has

SNUG Boston 2008

11

Return of the SystemVerilog Gotchas

its own gotcha, but that‘s another story...). Another solution in SystemVerilog is to declare the loop variables within the for-statement itself, like this: for (int k = 0; k < 16; k = k + 1) 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. 2.2 always procedures that are never executed The first gotchas paper ([1], in sections 3.2 and 6.4) has pointed out that while always_comb procedures and continuous assignments are executed at time 0 in order to initialize them, this is not true of regular always procedures. There are additional gotchas to this. We once had a case that looked something like this: always @* `ifdef FULL out = in ; `else out = 0; This did not work on some tools when FULL was not defined. It reduces to an always procedure with a null sensitivity list, and was never executed. There was nothing to trigger its execution. GOTCHA! Changing the always @* to always_comb would solve the problem, but we were not using SV. In the real case, the code inside the `ifdef FULL was actually a case statement of substantial size, so the code rewrite was more work. But the big problem was simply to understand why it did not work. A variation of this is where the right-hand side contains a variable, but the variable never changes. This can occur, for example, if the variable is initialized in the variable declaration, like this: logic a = 0 ; This is called a variable declaration assignment. Such initializations are executed before the always procedure is activated. Thus, although the variable‘s value changes at the time of initialization, no change in the value occurs after activation of the always procedure. This can also occur if the variable is initialized in an initial procedure at time 0. Since no order is defined between initial and always procedures, the initial procedure may be executed first. Or it can occur if there is some force to the variable value before the always procedure starts working.

SNUG Boston 2008

12

Return of the SystemVerilog Gotchas

Even if the right-hand side variable value later changes, the output of the always procedure will still not be initialized from the beginning of the simulation until the first time the variable changes later on. 2.3 Misuse of logical AND and OR Gotcha 53 in [3] and 6.11 in [1] are about mixing up the unary logical NOT (!) and bit-wise NOT (~) operators. This one is about the binary logical AND and OR (&&, ||) and bit-wise AND and OR (&, |) operators. The logical AND and OR operators treat their operands as either TRUE or FALSE, non-zero and zero, respectively. They return a 1-bit result, either 1‘b1 or 1‘b0 (or 1‘bx if the result is unknown). Thus, 2’b10 && 2’b01 is TRUE because both operands are non-zero and returns 1‗b1. This is like writing (2’b10 != 0) && (2’b01 != 0). On the other hand, the bit-wise operators treat each bit of the operands individually, size-extend the shorter operand to the length of the longer operand, and return an N-bit result, where N is the size of the longer operand. Thus, 2’b10 & 2’b01 is 2‘b00. For 1-bit operands, the logical and bit-wise operators behave the same. However, a myth has developed that says that you need to use logical operators for control signals and bit-wise operators for data-path signals. No! Verilog simulators have no understanding of ―control‖ and ―data-path‖. Both forms of operators simply work according to their definitions in the LRM, which are identical for one-bit operands. The gotcha which can occur is using logical operators instead of bit-wise operators where the operands are vectors. This mistake is very easy to make. It is simply to type the & or | character twice instead of once. And the code is perfectly legal. It's just wrong. Fortunately, it is uncommon to write code with logical operations on vectors, like this: a[31:0] && b[31:0] It is much more common and also much more readable to write it with explicit comparisons to zero, like this: (a[31:0] != 0) && (b[31:0] != 0) Thus, we can configure our Lint tool (and we should all be using a Lint tool) to flag logical ANDs and ORs with vector operands. As a coding guideline, I strongly recommend to use only bit-wise AND and ORs in synthesizable RTL, and not use logical ANDs and ORs at all. This has several reasons. One is that it avoids this gotcha. Another is that anything that can be written with the logical operators can be written with the bit-wise operators as well (by comparison to zero), whereas the reverse is not true. Writing

SNUG Boston 2008

13

Return of the SystemVerilog Gotchas

the comparisons to zero explicitly also makes the code more readable. That is what you should do if you really want to achieve the effect of logical operations on vectors. There are nevertheless two other differences between logical and bit-wise operators that fairness requires me to mention. One is that some code coverage tools check logical operators but not bitwise operators. But these can usually be configured to cover the bit-wise operators as well. The other difference is in short-circuiting. Short-circuiting is described in Gotcha 52 in [1] and 5.8 in [3]. The Verilog LRM up to now allowed, but did not require, short-circuiting on any operators. (See section 5.1.4 of 1364-2005.) In practice, however, many tools implement short-circuiting as in C, on logical operators, but not on bit-wise operators. In practice, short-circuiting did not make any difference in real synthesizable RTL descriptions. However, in behavioral or test-bench code, you might want the short-circuiting behavior. The upcoming SV-2009 LRM will codify this behavior (Mantis 997). In certain SV code involving auto-increment or auto-decrement operators (++ or --), shortcircuiting might make a difference even in synthesizable RTL code. But in those cases, you would probably want the operations to always be performed and not have short-circuiting occur, so there also the bit-wise operators would probably be better. 2.4 Zero replication constants Verilog has a special form of concatenation called replication or multiple concatenation. You write {N {expr}}, which replicates the expression N times. N, the replication constant, must be an expression with a constant value. For example, {b, {3{a, b}}} yields the same value as {b, a, b, a, b, a, b}. What happens if N is zero? The 1995 LRM does not say. Most tools replace the entire replication by 1‘b0. So {b, {0{a, b}}} becomes {b, 1’b0}. A true zero replication would actually be very useful. What do you want/expect to happen if the replication constant is zero? You want the replication to disappear entirely! The most common place where this occurs is where you use replication to add N leading zeros to an expression that is P-N bits wide in order to get a total of P bits. For example, if N is a parameter in the range 0 to 31, a[31:0] = {{N{1’b0}}, b[31-N:0]}; This works fine for N=1 up to 31. What happens if N is 0? Now you have a[31:0] = {{0{1’b0}}, b[31:0]}; and this turns into a[31:0] = {1’b0, b[31:0]};

SNUG Boston 2008

14

Return of the SystemVerilog Gotchas

Now your right-hand side is 33 bits instead of 32, and if you have a Lint tool, it may yell at you because of a size mismatch. But the only thing that happens is that you have an extra leading zero, which gets truncated. Not so bad. It does not affect the result. But what happens if the replication is not of leading zeros, but in the middle or end of your concatenation? Suppose it was like this: a[31:0] = {b[31-N:0], {N{1’b1}}}; Now with N=0 you get this: a[31:0] = {b[31:0], 1’b0}; That‘s not what you wanted. GOTCHA! The Verilog-2001 LRM attempted to deal with this gotcha by declaring zero replications illegal, but it did not help much. Now many tools will issue a warning on a zero replication, but engineers are infamous for ignoring warnings. Furthermore, since the vast majority of cases are the harmless leading zero cases, you can‘t find the one warning which points out a real problem. GOTCHA again! And even if you do find the real problems, the warning does not help you to actually solve them. The Verilog-2005 LRM attempts to deal with this in a better way. As we said, when the replication constant is zero, you want the replication to disappear entirely That is exactly what the 2005 LRM says should happen. In order for this to not cause the problem of having an expression of zero bits, the LRM also says that a zero replication can only appear as part of a concatenation where at least one element of the concatenation has a positive length. So {b, {0{a, b}}} is legal, but {{0{a, b}}} is not. Unfortunately, most tools are still not implementing this part of the 2005 LRM and are still doing the same erroneous behavior of the past. GOTCHA yet again! They probably do this for reasons of backwards compatibility. What can you do today if the current zero replication behavior will cause an error? Typically, intermediate variables, shift operations, and part-selects can be used to make sure that the code is correct for all values of the replication constant. For example, in our last case, a[31:0] = {b[31-N:0], {N{1’b1}}}; we can recode this as temp[63:0] = {b[31:0], {32{1’b1}}}; a[31:0] = temp[(63-N)-:32]; As a guideline, where a replication is used with a parameterized replication constant, you should verify that the code works correctly for the maximum and minimum values of the replication constant.
SNUG Boston 2008 15 Return of the SystemVerilog Gotchas

2.5 Negative replication constants What happens if the replication constant is negative instead of zero? In contrast to zero replication constants, which are very common and very useful, negative replication constants are not very useful and thus are also very rare in practice. If they do occur, it is usually a mistake. Like zero replications, the Verilog-2001 LRM also makes these illegal. But unlike zero replications, these remain illegal in the 2005 standard, and should cause compilation errors. However, many tools treat these in the same way as zero replications, turn them into 1‘b0, and just give a warning. So you both only get a warning, which many ignore, and it also ends up doing something strange. GOTCHA! Sometimes the warning just says that the replication constant is ―zero or negative‖, and then you have to examine it to see whether it is zero or negative. 2.6 Elaboration of unused illegal parameterized code Sometimes you write parameterized code which can be legal or illegal depending on the parameter value. However, you know that the illegal version is not used or is deselected when the parameter has such a value. In the following example, the parameter DEV_NUM determines how many times to instantiate module mm, each time with a different value of parameter S. The code allows as many as three instantiations, but it has been determined that only 2 are to be used in this version of the design, so only S0 and S1 are needed. S2 has been set to 0 since it will not be used. mm will not be instantiated using S2. Anytime S2 is to be used, it will be given a positive value. module mm #(parameter S=1)(input sig[S-1:0]); ... endmodule module top; parameter DEV_NUM = 2; parameter S0 = 2, S1 = 1, S2 = 0; wire sig[31:0]; generate for (genvar ii=0; ii <DEV_NUM; ii++) begin :loop mm mm #(.S((ii == 0) ? S0 : (ii == 1) ? S1 : S2 ) (.sig((ii == 0) ? sig[S0-1:0] : (ii == 1) ? sig[S1-1:0] : sig[S2-1:0]); end endgenerate endmodule

SNUG Boston 2008

16

Return of the SystemVerilog Gotchas

When we try to compile this, we get an error saying that we have written sig[-1:0], which has both an out-of-range index and is also in the wrong order, from low to high, whereas sig is declared as high to low, 31 to 0. This comes from the expression sig[S2-1:0]. But, you say, ii never gets to be 2! It does not matter. The code generated for ii = 0 will be (.sig((0 == 0) ? sig[2-1:0] : (0 == 1) ? sig[1-1:0] : sig[0-1:0]); And for ii =1, it will be (.sig((1 == 0) ? sig[2-1:0] : (1 == 1) ? sig[1-1:0] : sig[0-1:0]); It is true that in simulation, short-circuiting will occur, but in the elaboration stage of the compilation it sees sig[-1:0]. What can we do? In this simple example, of course, we can just set S2 to a positive number, but in the real case this came from, S2 needed to be 0. A solution in this case is to rewrite the code as follows: (.sig(sig[((ii == 0) ? S0 : (ii == 1) ? S1 : S2)-1:0]); In this way, the index needed is computed as part of a constant expression that is computed at the elaboration stage. It never tries to actually reference sig[-1:0]. There is an additional advantage to this recoding. In the original code, there is a conditional selection between sig[S2-1:0], sig[S1-1:0], and sig[S0-1:0]. Each has a different length. Even if S0 did have a legal value, the compiler would do size-extension of each to the length of the longest of them. This might not cause a functional problem (though it might in some cases), but at the very least, you get port size mismatch warnings from the tools. Sometimes the recoding is considerably more difficult than in this simple example. 2.7 Incorrectly written indexed part-select (V2K1) This one is nasty. I have seen it only once, but it was very difficult to find. A regular part-select is of the form [c1:c2], where c1 and c2 are constant expressions. The placement of such a part-select is therefore constant. V2K1 introduced indexed part-selects to allowed part-selects of constant width, but with variable positions. An indexed part-select has the form [n +: c] or [n -: c], where n can be a constant or a variable, and c is a constant

SNUG Boston 2008

17

Return of the SystemVerilog Gotchas

expression. Here we‘ll discuss the [n +: c] case, but the same gotcha can occur with [n -: c]. [n +: c] covers the bit-range [n : n+c-1] or [n+c-1 : n], depending on whether the variable is declared with a bit-range [high:low] or [low:high]. The compiler arranges the bits from the part-select in the same direction as specified in the declaration. Suppose you forget whether the indexed part-select is written +: or :+? It took me a few years to get it straight in my mind. What happens if your fingers are dyslexic and type them in the wrong order? Now we have [n :+ c]. This is the same as [n : +c] or simply [n : c]. If n is a variable, you get a compilation error, because variables are not allowed in regular part-selects. But suppose n as well as c is also a constant expression. This can be a completely legal expression. Example: logic [255:0] cucu; ... if (cucu[95:+32] == 0) ... // instead of cucu[95+:32] In this example, the user wants to check the value of the 32 bits 127 to 95 from the vector cucu, but by reversing the symbols of the indexed part-select operator, he instead got the 64 bits from 95 to 32. GOTCHA! If your coding guidelines are strict on bit-size matching and you use a Lint tool, then you have a good chance of detecting this error. For example, if you wrote if (cucu[95:+32] == 32’b0) ... // instead of cucu[95+:32] then the Lint tool could flag that the left-hand side of the comparison is 64-bits wide, whereas the right-hand side is only 32 bits wide, and would indicate that something is wrong. It could still take you time to figure out the problem, because the code looks correct, but at least you have a hint of the problem. It is possible to have a situation where even the size would remain the same, such as [15+:8] vs. [15:+8], both of which are 8-bits wide, but that is rarer. 2.8 String size-extension Most of us have gotten used to the idea that numerical operands in an expression are sizeextended 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.

SNUG Boston 2008

18

Return of the SystemVerilog Gotchas

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‖. 2.9 Macro expressions need to be in parentheses This gotcha exists in C as well. Suppose you have `define CUCU a+4 ... `CUCU * 12 You want to get (a+4) * 12. Since macros are pure text substitution, what you really get is a+4 * 12, which is a + (4*12), which is not what you wanted. This can happen when a macro defines an arithmetic or boolean expression that is then substituted into code next to an operator of higher precedence. In this example, the macro contains the addition operator, but is substituted into text next to a multiplication operator, which is of higher precedence.

SNUG Boston 2008

19

Return of the SystemVerilog Gotchas

I have seen this bug several times. The solution to this is to write macro expression definitions with enclosing parentheses, like this: `define CUCU (a+4) But this is not enough. The book Code Complete, section 5.9, shows that if you have a macro with arguments, then each use of the arguments also has to be enclosed in parentheses. For example: `define PR(x,y) (x*y) ... `PR(a+3,2) This will still give the wrong result, a+3*2 instead of (a+3)*2. Instead the macro has to be written like this: `define PR(x,y) ((x) * (y)) 2.10 Macro call within string literal If you have a string literal that contains a character sequence that looks like a valid text macro usage, is it considered to be a call to the text macro and substitution performed? Or is it just considered to be a random character sequence like any other within a string literal, with no semantic meaning? For example, if we have `define HI Hello initial $display("`HI, world"); is the result "`HI, world" or "Hello, world" ? The LRM has not been sufficiently clear. In practice, some tools have interpreted the LRM in one way and some have interpreted it the other way. This causes the problem that people have written code assuming that a text macro call inside a string literal is expanded, because that is what their tool does, and then the code no longer works when moving to a different tool. GOTCHA! One of the justifications given for expanding macros within a string literal has been that this is a very useful feature. The opposing opinion has been that this is inconsistent with the Verilog concept that a string literal is a single lexical token. Furthermore, SystemVerilog has added the ability to construct string literals (within macro text) using the `" token. The IEEE SV WG has resolved this issue in Mantis 1119 in accordance with the opinion that no expansion of any sort occurs within string literals. This means in addition that if a macro text definition contains a string literal, and that literal contains a character sequence that matches the name of a formal argument to the macro, it also is not recognized there as a call to the argument and not expanded. Thus, in this example,

SNUG Boston 2008

20

Return of the SystemVerilog Gotchas

module main; `define HI Hello `define LO "`HI, world" `define H(x) "Hello, x" initial begin $display("`HI, world"); $display(`LO); $display(`H(world)); end endmodule no expansion of macro calls or macro arguments occurs within the string literals and the result is: `HI, world `HI, world Hello, x 2.11 Null ports What is wrong with the following module header? module top( a, b, /* c */, d, e, f) ; The answer is that between ports b and d, there are two consecutive commas: module top (a, b,, d, e, f); How many ports does module top have? Six! The third port is called a "null port" or an "empty port". It has no name, size, or direction, but exists all the same. And it is legal syntax. It may even compile without any warnings. Until you try to instantiate and connect it. Then you start getting warnings about unconnected ports or if you connect the ports by position, you may get a type match error between the port type and the connection type. GOTCHA! This mistake is especially likely to occur when you list the ports one per line with a comma at the end and then delete or comment out the last one, like this: module top( a, b, // c

SNUG Boston 2008

21

Return of the SystemVerilog Gotchas

); When you get "unconnected port" warnings, and you can see that the number of connections is correct, it is a good bet that this is the problem. This error is also less likely to pass undetected by the tools when declaring ports in "ANSI-style," where the port direction and size as well as the port name appears in the module header. The following will probably not compile, for example: module top( input a, output b, // c );

3.0 SystemVerilog Gotchas
These are gotchas that are new in SV. 3.1 Types defined in different scopes This gotcha is stated explicitly in the 1800-2005 LRM in Section 6.9, but not emphasized. I have not seen it described in many SV trainings, either. But to many people, it is not intuitive. 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.

SNUG Boston 2008

22

Return of the SystemVerilog Gotchas

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 3.2 Arrays vs. queues In SystemVerilog 3.1a, pre-IEEE 1800, array and structure literals and expressions were written with curly brackets, like concatenations. For example: bit unpackedbits [1:0] = {1,1}; This made for confusion between these and concatenations, which had essentially identical syntax. It made life more difficult for tools also. In IEEE 1800-2005, the syntax of structure and array literals and expressions (now called "assignment patterns") was changed to require an apostrophe before the curly brackets, like this: bit unpackedbits [1:0] = '{1,1};

SNUG Boston 2008

23

Return of the SystemVerilog Gotchas

This is described in Gotchas 17 and 100 in [3]. However, there is an additional gotcha in this area. Even in IEEE 1800-2005, we still see some examples without the apostrophes that behave neither like regular concatenations nor like regular assignment patterns. For example, here is an example of a queue declaration with an initializer: integer q[$] = {3, 2, 7}; // An initialized queue of integers This initializes the queue array q to three elements, where q[0]=3, q[1]=2, and q[2]=7. We also have examples like the following, which describes insertion of a new element to a queue: q = {q[0:pos-1], e, q[pos,$]}; // insert 'e' at position pos Here is an example with string variables: string d[1:5] = '{"a", "b", "c", "d", "e"}; string p[]; p = {d[1:3], "hello", d[4:5]}; This creates the dynamic array p with contents "a", "b", "c", "hello", "d", and "e". This is obviously not a regular concatenation, whose elements can only be sized scalars or vectors, but not array slices (e.g., d[1:3]) or unsized integers (e.g., 3). These examples show a sort of concatenation where an element that is an unpacked array, such as d[1:3], is expanded into its individual members, as though you had written d[1], d[2], d[3]. There was a long discussion in the IEEE SV committee as to whether this syntax and these examples should be legal, or whether they should be considered errors in the LRM and queue concatenations should use apostrophes, like other assignment patterns. Tool support is not consistent. So do you use apostrophes or not? Only your compiler knows for sure. GOTCHA! In the end, it has been decided to allow all of these examples and define an ―unpacked array concatenation‖ that will have the shown behavior. The exact description is beyond the scope of this paper, but can be found in Mantis 1702, and is part of the draft for the next version of IEEE 1800, in 2009. 3.3 Using `` for concatenation within an escaped identifier Verilog users have always wanted the ability to construct an identifier name by gluing together two strings of characters. SV added this capability within text macros, allowing you to glue together two fixed character strings and/or macro arguments, using two consecutive ―back-tic‖ (accent grave) characters. For example,

SNUG Boston 2008

24

Return of the SystemVerilog Gotchas

`define foo(f) f``_suffix `foo(bar) expands to bar_suffix What happens if the left-hand side of this ―glue operator‖ is a back-slashed character string (i.e., an escaped identifier)? For example, suppose you have the following: `define RND_MACRO(in, out) mod \inst_``out (.in1(in),.out1(out)) `RND_MACRO(sig_in[1], sig_out[1]); What you want is the following result: mod \inst_sig_out[1] (.in1(sig_in[1]),.out1(sig_out[1])) You want to instantiate the mod module with an instance name that includes the name of the output signal. However, the output signal can be a bit-select, containing square bracket characters. In order for the name to include such characters, the created identifier has to be an escaped identifier. So you prefix the left-hand side of the glue operator with a backslash. The question is whether a double back-tic is recognized as a glue operator in this case. Normally in an escaped identifier, all the characters after the backslash, until the concluding white space, are considered part of the identifier name and lose any other special meanings they might normally have. So a plus character does not mean addition, a quotation mark does not start a string literal, and a square bracket does not indicate a bit-select. The LRM does not indicate what happens in this case. VCS does treat the double back-tic as a glue operator in this case, which is fortunate, because that is what you want. However, many other tools do not do so. GOTCHA! This issue came up to discussion in the IEEE SV committee as Mantis 1537. No consensus has been reached. However, there is a lot of sentiment that treating the double back-tic here as a glue operator is inconsistent and not backwards compatible with Verilog, but nevertheless a desirable capability. There were several proposals as to alternate ways to do this, but no proposal has been approved, and thus this will not be clarified any more in SV-2009. This means that tool behavior in this case will continue to be inconsistent. 3.4 Use of special macro character sequences outside of macros SV-2005 (Section 23.2) added some new capabilities in text macros. Normally, quotation marks (" ") begin and end strings literals. Everything between the quotation marks is considered part of the literal. That means that you could not construct a string literal containing a call to a macro (See Section 2.10, above). Nor could a string literal appearing

SNUG Boston 2008

25

Return of the SystemVerilog Gotchas

inside macro text contain use of a macro argument. These would just be considered part of the character string comprising the literal. So " `A " is a string literal with four characters: space, back-tic, ―A‖, and another space. The `A is not recognized as a call to the macro A. SV added a `" character sequence for macros that is transformed into a quotation mark in the macro expansion, but still allow macro arguments and macro calls to be recognized correctly. SV also added a `\`" to generate a \" character sequence, and the double back-tic (``) sequence to act as a ―glue operator‖, as described in the preceding section in this paper. The LRM says this: ―In SystemVerilog, the macro text can also include `", `\`", and ``.‖ The question is, can these special character sequences be used outside macro text as well? The LRM does not say explicitly whether they can or cannot. It only describes them in the context of macro text, but some people apparently thought either that the LRM was only saying that they can also be used in macros or decided to extend the standard to allow them elsewhere as well. While many tools implement the more restrictive interpretation of the LRM, which does seem its plain meaning, the VCS implementation allows them elsewhere as well. And where a tool has an extra capability, by golly, some people are going to use it. Many of those people are unaware that other tools do not implement this extension, and their code no longer compiles when they try it on another tool. GOTCHA! 3.5 Are spaces around macro arguments dropped? One of the ways in which text macros are different from most of the SV language is that white space in macro text is not ignored. That is because text macros perform text substitution without interpretation of their contents. The macro definition has no knowledge of how and where the macro will be used. Maybe it will be used in a place where white space has significance. One aspect of this is when an actual macro argument is substituted for the formal argument into the macro text. Is the white space around the macro argument considered part of the argument or not? For example, you can call a macro A with an argument, like this: `A( arg )

Is the argument considered to be ―arg‖ and the spaces around it have no significance, or is the argument considered to be ― arg ―? In Verilog, it is very difficult, maybe impossible, to find a case in which this makes a difference. That is why this issue was not important in the past. But in SystemVerilog, where you can construct a string literal from macro arguments, it now becomes important. For example, `define A(arg) `"AAargBB`"
SNUG Boston 2008 26 Return of the SystemVerilog Gotchas

$display ( `A( 0 ) ) ; Does this display "AA0BB" or "AA 0 BB" or "AA0 BB", etc. Again, it turns out that not all tools do the same thing. GOTCHA! Most tools do drop the white space around the arguments both before and after the argument, but there are exceptions. 3.6 String equality and compare functions have opposite return values SV introduced a string data type and a number of operations that can be performed on it. In SV-2005, Table 4-2 describes the string equality operation: str1 == str2 works like the regular == equality operator and returns 1 if the strings are equal and 0 if they are not. The LRM also defines the compare() string comparison method. Intuitively, you would expect this to work the same as the other comparison operator, ==. The LRM does not say otherwise. It just says, ―str.compare(s) compares str and s, as in the ANSI C strcmp function,‖ without specifying the behavior of strcmp. You might not remember or be aware of the definition of strcmp, or you might simply be unaware that compare() is defined in terms of strcmp. However, the return values of strcmp are the opposite of those of the equality operator. So compare() returns 0, not 1, if the strings are equal and 1 if the strings are different. GOTCHA! Thus, where you would write ―if (str1 == str2)‖, you must write ―if (!str1.compare(str2)). See also Solvnet article 022593 (https://solvnet.synopsys.com/retrieve/022593.html) on this subject. A related Verilog gotcha is when comparing two vectors. Many people remember that the bitwise XOR operator ^ can be used to compare two vectors. People often gets its polarity mixed up, and forget that vector1 ^ vector2 is 1 if they are different and 0 if they are the same. 3.7 Glitches in unique/priority The unique and priority keywords that are new in SV are a great feature, but they have pitfalls. The two gotchas papers have shown some (6.14 in [1], 2.1 and 2.2 in [2]), and we present others in this paper as well. One problem in the definition of how they work in SV-2005 is that glitches can occur. That is, variables can go through intermediate state combinations when they are changing that cause unique and priority violations to occur. These cause false warnings to be displayed, even though no violation occurs after the signal values have stabilized. The following is a toy example, but it illustrates the point:

SNUG Boston 2008

27

Return of the SystemVerilog Gotchas

always_comb unique case({ff1_d,ff1}) 2'b00: o = 1'b0; 2'b11: o = 1'b1; endcase always_comb ff1_d = ff1 && 1 ; always_ff @(posedge clk) ff1 <= in; In this example, the unique case asserts that ff1_d and ff1 are the same. When the always_ff procedure executes, it assigns a value to ff1, which is then propagated to ff1_d. All the simulators tested issued a violation message of the unique case between the assignments to ff1 and ff1_d. Now you have to distinguish between the true violations and the false violations. GOTCHA! Intel‘s CPU projects suffered from this problem, and we filed this with the IEEE SV WG as Mantis 2008. A solution was devised and it will be part of the SV-2009 revision of the LRM. A high-level description of the solution is this: if an always_comb procedure containing a unique or priority if-else or case statement is triggered more than once during the same time step, then only violations detected during the last execution of the procedure during the time step will be reported, and violations detected during previous executions of the procedure during the same time step will be flushed. This will work for zero-time glitches in the values of the variables. It will not help for glitches whose length is more than a single time step, but it is assumed that at RTL level, most of the glitches will be zero-time. 3.8 Glitches in immediate assertions Just as glitches can occur with unique and priority, as described in the previous section, they can also occur with immediate assertions. Here is an example: assign not_a = !a; always_comb begin out = a && x || not_a && y; assert (out == a ? x : y); end Here, the always_comb procedure implements a multiplexer. The always_comb may execute twice when a changes. The assertion may incorrectly fire on the first execution, before the change to not_a has been applied, reporting a failure that is really false from the point of view of the user. GOTCHA!

SNUG Boston 2008

28

Return of the SystemVerilog Gotchas

It is not surprising that the same problem occurs in both constructs, as unique and priority may indeed be thought of as special types of immediate assertions. The glitch problem in immediate assertions can be even more serious, because these can contain "action blocks" to be executed when the assertion fires. This problem was filed with the IEEE SV WG as Mantis 2005. A solution was devised which has the same basic idea as the solution for unique and priority, described in the previous section, and this will also be part of the SV-2009 LRM. However, there is a significant difference between the two solutions. For unique and priority, the committee found that no one was interested in leaving the glitchy behavior available, and so their behavior was redefined so as to eliminate the glitches. No change in the code by the user is required in order to get the new behavior. For immediate assertions, the committee decided not to change the existing behavior, in order to avoid problems of backward compatibility. Remember that while unique and priority are limited to very specific contexts, immediate assertions can be used much more generally, and it was feared that changing the existing behavior might cause problems. So a variation of immediate assertions was defined, called deferred assertions. Whereas a regular immediate assertion is specified by writing assert, a deferred assertion will be specified by writing assert #0. Verilog users are used to the meaning of #0 as a sort of "delta delay", so this syntax can be easily understood. 3.9 Assignments in expressions Our abstract mentions the infamous C gotcha of using an assignment instead of a comparison in an expression by mistake, as in "if (a=b)" instead of "if (a==b)". SystemVerilog does not let you do this. To use an assignment in an expression, you have to add an extra pair of parentheses: "if ((a=b))". The LRM relates to this as preventing the C gotcha. So does Gotcha 44 in [3]. In fact, the authors in [3] note that this unavoidably creates a new gotcha, where someone will try to write as in C, a language he is familiar with, without the extra parentheses, and then not understand why it fails compilation. The fact is, however, that SystemVerilog's requirement of extra parentheses only reduces the risk of hitting this gotcha, but does not prevent it. If you write an assignment instead of a comparison and enclose the assignment in parentheses, the gotcha will still occur. The code will be legal and wrong, and the simulator compiler will be silent about it.

SNUG Boston 2008

29

Return of the SystemVerilog Gotchas

You might ask why you would write "if ((a=b))", with extra parentheses. You probably would not write such a simple expression that way, but for a slightly more complex expression, it is not at all unlikely. Consider something like the following: always_comb b = (a=1) ? 1 : 0 ; This line is quite legal, but likely unintentional. We had such a case, in a more complex statement, and no tool even issued a warning. GOTCHA! 3.10 Uneven coverage bin distribution Suppose you want to do coverage of a variable or expression that can have a range of values. The bins construct allows you to create a separate bin for each value in the given range list (an array of bins) or a single bin for the entire range of values. You can also create a fixed number of bins and have the values automatically distributed across the bins. To create a separate bin for each value, square brackets, [], follow the bin name. To create a fixed number of bins for a set of values, you specify the number of bins inside the square brackets. For example: bins fixed [4] = {1:10, 14, 15}; The 12 possible values are distributed as follows: <1,2,3>, <4,5,6>, <7,8,9>, <10,14,15>. That works fine where the number of values can be distributed evenly among the bins. What happens if the number of values is not divisible by the number of bins? The LRM says, "If a fixed number of bins is specified and that number is smaller than the specified number of values, then the possible bin values are uniformly distributed among the specified bins. The first ‗n‘ specified values are assigned to the first bin, the next ‗n‘ specified values are assigned to the next bin, etc. ... If the number of values is not divisible by the number of bins, then the last bin will include the remaining items. For example: bins fixed [4] = {1:10, 1, 4, 7}; The 13 possible values are distributed as follows: <1,2,3>, <4,5,6>, <7,8,9>, <10,1,4,7>."

SNUG Boston 2008

30

Return of the SystemVerilog Gotchas

This example looks reasonable. But the key sentence here is "If the number of values is not divisible by the number of bins, then the last bin will include the remaining items." This can actually create some significant distortions. Suppose you have N bins and (P*N)-1 values, where P is some integer. For example, 499 values in 100 bins. For a distribution as uniform as possible among the bins, you would expect to see 4 values in one bin and 5 values in each of the other bins. What will actually happen is that the first 99 bins will get 4 values each and 103 values in the last bin! GOTCHA! A proposal was submitted to the SV Working Group in Mantis 2055 to fix this and make the distribution truly uniform, but it was rejected on the grounds that it is not backwards-compatible. The thought behind the existing behavior is that it is easy and fast to implement. However, it was shown that the new proposal would not be complex, either. 3.11 const variables are not parameters SystemVerilog has added the ability to declare a variable as "constant" by adding the const keyword to the declaration: const logic a = 0; const variables can be either static or automatic. Here we will just talk about static const variables. Automatic const variables are a little different. A const variable is assigned a value in its declaration and cannot be assigned a value in a procedural assignment. Many people see this and think that if it is a constant, then it can be used in place of a constant, like a parameter, for example in a range specification, like this: const integer a = 3; logic [a:0] b; And then they don't understand why they get a compiler error. GOTCHA! The catch here is that a const variable is still a variable, and can only be used where a variable can. Its value is assigned after compilation and elaboration, at the beginning of run-time. Anywhere the language requires that an elaboration-time constant be used, such as in the specification of the range of a data object's dimension, a const variable cannot be used. For example, anywhere the language syntax specifies a "constant_expression", only elaboration-time constants may be used. The confusion arises because the standard uses the term "constant" with more than one meaning. In fact, most uses of the term "constant" in the standard mean elaboration-time constants.

SNUG Boston 2008

31

Return of the SystemVerilog Gotchas

If so, what is the benefit of having static const variables? The truth is that defining a variable as const does not convey upon it added abilities, with a few minor exceptions. For the most part, its benefit is in preventing it from even accidentally and incorrectly being assigned a new value, in documenting its intent to be initialized but not overwritten, and having the compiler enforce that restriction. 3.12 The static initialization order fiasco (See http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12 for the name. Thanks to Dave Rich from Mentor for pointing it out.) The discussion in this section is limited to static variables. Automatic variables are a little different. In both Verilog and SystemVerilog, there is no guaranteed order of execution between initial and always procedures. This is a frequent source of problems, as pointed out in Gotcha 56 in [3]. However, you don't need always procedures to have execution order problems with initial procedures and initializations. Naturally, SV does not guarantee order of execution between initial procedures. So in the following: reg a, b; initial a = 0; initial b = a; there is no guarantee that the first initial procedure will execute before the second and therefore there is no guarantee as to the value that will be assigned to b. Verilog-2001 introduced "variable declaration assignments" (VDAs), an initialization assignment to a variable in its declaration. This was defined as being equivalent to doing the assignment in an initial procedure. So the following: reg b; reg a = 0; initial b = a; was the same as the first code version above. SystemVerilog has defined that VDAs are executed before initial and always procedures, so now this code is guaranteed to initialize a before b. However, no order is guaranteed between VDAs, so that the following:

SNUG Boston 2008

32

Return of the SystemVerilog Gotchas

reg a = 0; reg b = a; has the same problem as our original code. Many people understand this. However, fewer people understand that the same is true for const variable declarations. Many people think of const variables as being like parameters and expect that the following will work: const logic a = 0; logic b = a; However, const variables are still variables. The only difference is that a const variable must be assigned a value in its declaration and may not be assigned a new value afterwards.

4.0 Synthesis Gotchas
4.1 always_comb does not guarantee combinational logic One of the big traditional synthesis gotchas of Verilog has been that it is so easy to write an always procedure that is intended to model combinational logic, but actually synthesizes as a latch. Simulators do not give you any warning when this happens. Synthesis and Lint tools tell you that you have a latch, but they do not distinguish between intentional and unintentional latches. That is not so bad if your design does not contain many intentional latches, but if you do use latches, then the latch report starts to be big and it is more difficult to find the unintentional latches. Enter SV‘s new always_comb and always_latch procedures. Now I can indicate explicitly the intent of my always procedures as combinational or latches. But always_comb does not guarantee that the code you write will actually model combinational logic. If the code does not assign a value to the output under all input conditions, it will still model latched logic, not combinational logic. The always_comb keyword indicates your intent, but does not guarantee that your intent is actually implemented. Well then, my simulator will at least tell me that I made a mistake, right? Don't count on it. The 1800-2005 LRM says in Section 11.2, ―Software tools can perform additional checks to warn if the behavior within an always_comb procedure does not represent combinational logic, such as if latched behavior can be inferred.‖ The key word is ―can‖. That is, tools may perform such additional checks, but they are not required to. And in fact, most simulators do not do so (today). You can write an always_comb procedure that will model and synthesize a latch, but it will pass simulator compilation silently. Simulators

SNUG Boston 2008

33

Return of the SystemVerilog Gotchas

do not like to know anything about synthesis. It makes extra work for them. GOTCHA! That is, you cannot depend on simulators to detect non-combinational always_comb procedures. Synthesis tools and Lint tools will, however, now be able to distinguish between intentional and unintentional latches. However, you still cannot rely on simulators to give you any information about this. The SV-2009 LRM draft changes that ―can‖ to ―should‖, in order to encourage tool developers to implement such checks. Some simulator developers opposed that change, saying that for nonsynthesis tools, it is not well-defined exactly what check they should perform. However, the proponents of the change said that mostly what was wanted is a check that the outputs of the always_comb procedure are assigned a value under all input conditions. The new wording still leaves these checks non-mandatory, so no one will be able to claim that a tool is non-compliant because it missed some corner case. This change was made in Mantis 1828. 4.2 My flip-flop is a latch! We all know that if you write a supposedly combinational always procedure incorrectly, by not assigning a value to an output of the procedure under all conditions, then you will get a latch from synthesis. This also makes some sense to us, because we know that we write latches in RTL in a way that is very similar to combinational always procedures. In Verilog-1995, for both latches and combinational logic, we write always with a sensitivity list that includes all the signals that are read within the procedure. In Verilog-2001, we use always @* for both. In SystemVerilog, there are separate keywords, always_comb and always_latch, but these only indicate intent. They behave identically. But how does it happen that we write code that looks like it should create a flip-flop and we still get a latch out of it? A normal flip-flop is written something like this: always @(posedge clk or negedge rst_n) if (!rst_n) out <= 1’b0 ; else out <= in; Suppose we write the following: always @(posedge clk or negedge rst_n) if (!rst_n) out <= 1’b0 ; Here the signal out is assigned a value when the asynchronous reset is active and is never overwritten by data loaded at the clock edge. This is equivalent to the following:

SNUG Boston 2008

34

Return of the SystemVerilog Gotchas

always @(rst_n) if (!rst_n) out <= 1’b0 ; This is clearly a latch style of code. This example is not so bad. You can look at the original code and see that there is only a reset condition and that no data is loaded otherwise. However, other cases are less obvious, such as this: always @(posedge clk or negedge rst_n) if (!rst_n) out[31:0] <= 0 ; else begin out[31:18] <= in1; out[16:11] <= in2; out[10:00] <= in3; end Here out is a 32-bit register with three fields, bits 31-18, 16-11, and 11-0. Bit 17 is not used. This leaves bit 17 with an asynchronous reset and no data load. Synthesis and Lint tools will tell you that bit 17 is a latch, even though you think you wrote a register of 32 flip-flops. GOTCHA! This is actually harmless, but can be quite surprising and confusing if you are unaware of this behavior. The day before I wrote this, it actually pointed out an error in real code. A user reported that he has this code (slightly edited): always @(posedge clk or negedge reset_n) if (!reset_n) begin a_en <= 1'b1; a_err <= 1'b0; b_en <= 1'b1; b_err <= 1'b0; end else if (wr & (address[11:0] == DDPAR))//DDPAR is a parameter begin a_en <= data[0]; a_err <= data[1]; b_en <= data[2]; b_err <= data[3]; end else if (cond) begin a_err <= a_done; b_err <= b_done; end

SNUG Boston 2008

35

Return of the SystemVerilog Gotchas

The user complained that his Lint tool indicates that a_en and b_en are latches. Why? This does not look like the case described above. Here a_en and b_en are assigned data values in non-reset conditions as well. Further study showed that the parameter DDPAR was defined as 16'h3508, a 16-bit value where bits 12 and 13 are non-zero, and it is being compared erroneously to only a 12-bit address. Thus, the comparison result is always false, and that part of the code is therefore ignored, as if it did not exist. That leaves us with only a reset assignment and no data assignment to a_en and b_en, and therefore they became latches. GOTCHA again! Since this gotcha is really harmless, you just need to be aware of this behavior, and then you will know why you get latch reports. 4.3 Myth: default/full_case/unique/priority prevent latches It is well known that for an always procedure to synthesize to combinational logic, you must assign a value to each of its outputs under all combinations of input conditions. Otherwise a latch is formed. How do you deal with this in a case statement? always_comb case (sel[1:0]) 2’b10: out = a; 2’b11: out = b; endcase This case statement assigns a value to out only for two of the four input combinations. In order to prevent a latch from being formed, we need to assign a value to out for the other two input combinations as well. We can add additional lines to the case statement for each of the additional combinations, but for large case statements with a large number of possible combinations, that can be very unwieldy. Another method is to add a default clause to the case statement, like this: always_comb case (sel[1:0]) 2’b10: out = a; 2’b11: out = b; default: out = 1'b0 ; endcase Or to add a full_case synthesis pragma, like this: always_comb case (sel[1:0]) // synopsys full_case 2’b10: out = a ; 2’b11: out = b ;

SNUG Boston 2008

36

Return of the SystemVerilog Gotchas

endcase The full_case pragma acts like adding a ―default: out = 'x;‖ clause to the case statement, and specifies that the output value for all unspecified case expression values is "don‘t care", and the synthesis tool is free to assign any value it wishes in order to optimize the implementation of the logic. In SV, the priority and unique keywords can be used instead of the full_case pragma. (priority is like a "full_case" pragma whereas unique is like a "full_case parallel_case" pragma combination.) All these methods will work for this code and prevent latch logic from being synthesized instead of combinational logic. As a result, many coding guideline documents specify one of these methods as standard methodology to insure that latches will not be generated. It Ain‘t Necessarily So. Take this case: always_comb unique case (sel[1:0]) // synopsys full_case 2’b00: out = 1’b0; 2’b01: out = 1’b0; 2’b10: if (cond) out = a; 2’b11: out = b; default: out = 1’b0; endcase Here we have used all the methods together: the case statement is complete, with a default clause, with a full_case pragma, and even unique pre-pended to it. None of this will help. A latch will still be formed. Why? Because there is still an input condition for which out is not assigned a value: if sel[1:0] is 2’b10 and cond is 0. The code will go to the 2’b10 branch of the case, but the condition of the if statement is false, and the else branch is null. No value is assigned to out in this case. GOTCHA! All the methods mentioned have the effect of covering all values of the case expression and thus that the list of case items is complete. However, they do not guarantee that within the case items, all the outputs are assigned values for all possible input combinations. Here is another variation of this situation: always_comb case (sel[1:0]) 2’b10: begin out1 = a; out2 = 1’b1; end 2’b11: begin out2 = b; end default: begin out1 = 1’b0; out2 = 1’b1; end endcase

SNUG Boston 2008

37

Return of the SystemVerilog Gotchas

In this variation, the case item list, together with the default clause, covers all possible input combinations, but one of them assigns a value only to one of the two output variables. In such a case, neither the default clause, nor a full_case pragma, nor unique or priority will prevent out1 from being synthesized as a latch. However, there is one way to handle this that will guarantee that latches will not be formed. We call this a ―default pre-assignment‖. That is to assign default values to all the outputs of the combinational logic before the if-else and case statements, as in this example: always_comb begin out1 = 1’b0; out2 = 1’b1; case (sel[1:0]) 2’b10: begin out1 = a; out2 = 1’b1; end 2’b11: out2 = b; endcase end This does guarantee that out1 and out2 will be assigned values within the always_comb procedure for every input combination, if not by the case statement, then by the pre-assignment. Until SV, this worked fine. But now, SV‘s unique keyword has introduced a new gotcha into the use of default pre-assignments. One uses unique to assert that the case items are mutually exclusive, i.e., that only one case item can match the case expression simultaneously. The advantage of unique over the parallel_case pragma is that unique causes the simulator to issue a violation message if the unique-ness of the case statement is violated. But unique also includes the effects of a full_case pragma. In particular, if the case statement does not include an explicit default clause, unique effectively adds an implicit "default: out = 'x;" case item to the case statement, but only for synthesis tools, not for simulators. See [18] for a fuller discussion of this. The result is that if the case expression has a value which does not match any of the case items, the simulator will use the default pre-assignment value, whereas the synthesis tool will use the implicit default don't care assignment and choose whatever value it likes. Weirdly, the unique construct, which had a goal of preventing synthesis-simulation mismatches, can itself cause a mismatch. For this and other reasons, SV-2009 will include a new unique0 construct, which will be like parallel_case without full_case, checking unique-ness of the case items, but allowing for none of them to match as well. Think of unique0 as meaning zero-one-hot whereas unique means one-hot. The details can be found in Mantis 2131.

SNUG Boston 2008

38

Return of the SystemVerilog Gotchas

4.4 Why is my combinational logic considered sequential? As discussed previously, you can write code that is intended to model combinational logic, but actually synthesizes to a latch. This happens if the output variable is not assigned a value under all possible input combinations. Suppose a particular combinational always procedure has several output variables. As in usual in combinational logic, you have written the procedure with blocking assignments, whereas you use nonblocking assignments for latches and flip-flops. All of the output variables but one are modeled correctly. An assignment to one of them was omitted in some case, as in this example from earlier: always_comb case (sel[1:0]) 2’b10: begin out1 = a; out2 = 1’b1; end 2’b11: begin out2 = b; end default: begin out1 = 1’b0; out2 = 1’b1; end endcase out1 synthesizes to a latch instead of to combinational logic. You are as yet unaware of this. You get messages from your synthesis or Lint tool that you have used blocking assignments instead of nonblocking assignments for out2 in a sequential procedure, and you ask yourself, ―What sequential procedure??‖ It does not occur to you that one of the output variables has turned into a latch. And even if it did occur to you, you would say to yourself, ―Maybe the procedure is sequential for some variable, but I can see that this one is combinational, that it is assigned a value in all situations.‖ You might even curse buggy tools. What has happened is that once the tool has determined that one of the variables in the procedure models a latch, the entire procedure is considered sequential, and therefore the tool expects nonblocking assignments on all of the variables. GOTCHA! Messages of this sort are a sign that one of the output variables in the procedure has turned into a latch. The messages about blocking assignments used in a sequential procedure don‘t tell you which one, though. For that, you have to look for the messages about inferred latches. 4.5 A synthesis engine is not as smart as a formal engine We encountered this problem several times. It is not a language gotcha, but a true synthesis gotcha. The following code is an example of the problem:

SNUG Boston 2008

39

Return of the SystemVerilog Gotchas

for (int i = 0; i < N; i = i + 1) if (i == var) array[var] = f(i); That is, we have a loop of N iterations. On each iteration, we compare the value of the loop index to some variable, and if their values are equal, then we do an assignment to a word whose index is equal to the value of that variable. When the loop is unrolled, we get N conditional assignments to a variable-indexed word of the array. Of course, all N assignments are to the same word, the word whose index is var, and only one can be executed. All the tools we saw turned this into very large logic with very high run-time and memory consumption. But really we know that for each iteration, the assignment will be executed only if the loop index value i is equal to the value of var. So instead of writing array[var], we can write array[i]. Remember that when loops are synthesized, the loop variable turns into a constant value for each iteration. Then we get N conditional assignments to the array, but each to a different, constantindexed word. This simple, almost trivial change makes a tremendous difference in the results. The synthesis engine is not sophisticated enough to make this optimization. For example, we had an always_ff procedure that contained the following code excerpt in the middle of its body: for (int i = 0 ; i < 64 ; i = i+1) if (i == vf_g) begin vm_mb[vf_g][2] <= d_del[7] ; vm_mb[vf_g][1:0] <= d_del[1:0]; end Changing the subscript for vf_g to i reduced the cell count by over 60K ! You might ask why the loop is needed at all, why not just write begin vm_mb[vf_g][2] <= d_del[7] ; vm_mb[vf_g][1:0] <= d_del[1:0]; end The answer is that this was part of a much larger code segment. It made sense in context to use the loop. This is often true. You can test the effect yourself with this simple test case: module test(output reg[255:0] tmp, input[255:0] a, input[7:0] j); always @(a or j) for (int i=0; i < 256; i = i +1) // 256 latches
SNUG Boston 2008 40 Return of the SystemVerilog Gotchas

if(i==j) tmp[j] <= a[j]; // BAD! // if(i==j) tmp[i] <= a[i]; // GOOD! endmodule We also tried the intermediate cases in a synthesis tool, i.e., using the variable j just on the lefthand side or just on the right-hand side. We found that using j on either side significantly increases the area, but using it on the left-hand side explodes the run-time as well. I recently found that Solvnet article 002218 (https://solvnet.synopsys.com/retrieve/002218.html) talks about problems with loops in the old pre-Presto HDL Compiler, such as with conditional assignments to arrays in loops. However, that article states that those limitations no longer exist in Presto. Here we have seen that certain cases can still cause problems in Presto and in other synthesis tools as well.

4.6 Asynchronous reset loops in flip-flops The code for a simple flip-flop with asynchronous reset looks something like this: always @(posedge clk or negedge rst_n) if (!rst_n) out <= 0 ; else out <= in; Suppose that we want to describe in this code not a single register, but an entire array of registers. We might write a loop that iterates over each of the words of the register, like this: reg [15:0] out [0:N] ; reg [15:0] in [0:N] ; integer i; always @(posedge clk or negedge rst_n) for (i=0; i<N; i=i+1) begin if (!rst_n) out[i] <= 0 ; else out[i] <= in[i]; end If you are unlucky, you will only get a message from your synthesis tool telling you that this is not synthesizable. If your tool is more friendly, then it might tell you that the asynchronous reset needs to be at the top of the always procedure. GOTCHA!

SNUG Boston 2008

41

Return of the SystemVerilog Gotchas

This mistake is frequently made and not understood even after getting an error message. It is not enough for the asynchronous reset condition to be at the top of the loop body. If it is inside the loop body, it is no longer at the top of the always procedure, which is what synthesis tools require. The code has to be written like this: always @(posedge clk or negedge rst_n) if (!rst_n) for (i=0; i<N; i=i+1) out[i] <= 0 ; else for (i=0; i<N; i=i+1) out[i] <= in[i]; The code has to describe the reset of the entire array first, and only then the data load. This requires using two loops instead of one. In SystemVerilog, this gotcha is less likely to be encountered because one does not usually need a loop to reset the array. One can usually reset the entire array in a single statement, like this: Always_ff @(posedge clk or negedge rst_n) if (!rst_n) out <= '{default:0} ; else for (int i=0; i<N; i=i++) out[i] <= in[i];

5.0 Conclusions and Recommendations
SystemVerilog is a good language, but it has gotchas. SystemVerilog has gotchas, but it is a good language. Don‘t give up, but be aware and be careful. Where possible, prepare coding guidelines to prevent gotchas. Check for them using Lint tools. In code reviews, look for those gotchas that your Lint tool does not check. Remember gotchas when you come to debug problems. Consider whether the symptoms remind you of any gotchas you know about. When you meet a new gotcha, spread the word among your colleagues, and think about finding a way to prevent it or to detect it earlier. If you have an idea how to improve the language so as to remove or at least reduce a gotcha (preferably in a backwards-compatible way), tell the IEEE SV WG.

SNUG Boston 2008

42

Return of the SystemVerilog Gotchas

6.0 Acknowledgements
A very big thanks to Chris Spear (Synopsys) for reviewing this paper thoroughly and making great suggestions! Thanks to Stuart Sutherland and Don Mills for encouragement to follow in their footsteps. Thanks to Cliff Cummings for pushing me to submit a paper to SNUG and for a special friendship.

7.0 References
[1] Stuart Sutherland and Don Mills, ―Standard Gotchas: Subtleties in the Verilog and SystemVerilog Standards That Every Engineer Should Know,‖ SNUG Boston 2006 [2] Stuart Sutherland, Don Mills, and Chris Spear, ―Gotcha Again: More Subtleties in the Verilog and SystemVerilog Standards That Every Engineer Should Know,‖ SNUG San Jose 2007 [3] Stuart Sutherland and Don Mills, Verilog and SystemVerilog Gotchas: 101 Common Coding Errors and How to Avoid Them, Springer, 2008, ISBN 978-0-387-71714-2 [4] IEEE Std 1364-1995, IEEE Standard Hardware Description Language Based on the Verilog® Hardware Description Language, IEEE, 1995, ISBN 1-55937-727-5 [5] IEEE Std 1364-2001, IEEE Standard Verilog® Hardware Description Language, IEEE, 2001, ISBN 0-7381-2827-9 [6] IEEE Std 1364-2005, IEEE Standard for Verilog® Hardware Description Language, IEEE, 2005, ISBN 0-7381-4851-2 [7] IEEE Std 1800-2005, IEEE Standard for SystemVerilog—Unified Hardware Design, Specification, and Verification Language, IEEE, 2005, ISBN 0-7381-4811-3 [8] Mantis, http://www.eda.org/svdb [9] Stuart Sutherland, Simon Davidmann, and Peter Flake, SystemVerilog for Design, 2ed, Springer, 2006, ISBN 978-0-387-33399-1 [10] Chris Spear, SystemVerilog for Verification: A Guide to Learning the Testbench Language Features, 2ed, Springer, 2008, ISBN 978-0-387-76529-7 [11] Shivakumar Chonnad and Needamangalam Balachander, Verilog: Frequently Asked Questions, Springer, 2004, ISBN 0-387-22834-9

SNUG Boston 2008

43

Return of the SystemVerilog Gotchas

[12] Doulos Ltd, SystemVerilog Golden Reference Guide, Version 4.0, January 2006, ISBN 09547345-3-X [13] David Black and Lewis Sternberg, ―Avoiding Verilog Nightmares During Verification,‖ SNUG San Jose 2000 [14] Don Mills and Clifford E. Cummings, ―RTL Coding Styles That Yield Simulation and Synthesis Mismatches,‖ SNUG Europe 2001 [15] Duane Galbi and Lok Kee Ting, ―RTL X's - A Treasure Trove of Trouble,‖ SNUG Boston 2002 [16] Mike Turpin, ―The Dangers of Living with an X (bugs hidden in your Verilog)‖, SNUG Boston 2003 [17] Cliff Cummings, ―Verilog Nonblocking Assignments With Delays, Myths and Mysteries,‖ miniSUNG Ottawa 2003 [18] Cliff Cummings, ―SystemVerilog's priority & unique - A Solution to Verilog's "full_case" & "parallel_case" Evil Twins!,‖ SNUG Israel 2005 [19] Moe Kinney, Denise Powell, and Ray Yock, ―The Living Hell of Identifiers and define_name_rules,‖ SNUG Boston 2005 [20] Colin Paul Gloster, ―ACCU Book Review: The Design and Evolution of C++,‖ http://accu.org/index.php/book_reviews?url=view.xqy?review=14179489152797087495 [21] http://www.hyperdictionary.com/computing/gotcha [22] Yossi Ginzburg, Eyal Skulsky, Ziv Baum, and Tzahi Sabo, "Are you satisfied with your constraints? Eight ways to misuse Vera solver," SNUG Israel 2007

8.0 About the Author
Shalom Bresticker is a Senior CAD Engineer in the LAN Access Division in Intel's Jerusalem design center. At Intel, Shalom supports front-end logic design and verification tools and methodologies. He joined Intel in 2005 after more than 20 years at Motorola Semiconductor Israel, later Freescale Semiconductor Israel, in VLSI design and verification. Shalom started using Verilog in 1989, and started participating in the IEEE 1364 Verilog standards committee in 1995, later editing Version C of the 1364-2001 LRM and most of the 1364-2005 LRM. In recent years, he has participated in the IEEE 1800 SystemVerilog standards committee and the Accellera Verilog-AMS standards committee. He is a self-acknowledged Verilog and SystemVerilog bigot.

SNUG Boston 2008

44

Return of the SystemVerilog Gotchas

Shalom holds a BSE from Princeton University and an MSEE from the Technion-Israel Institute of Technology. He serves on the Technical Program Committees for SNUG Israel and Europe, DVCon, and Intel's Design and Test Technology Conference.

SNUG Boston 2008

45

Return of the SystemVerilog Gotchas

Sign up to vote on this title
UsefulNot useful