✔ Đào Tạo Kỹ Sư Thiết Kế Vi Mạch cùng Semicon

11/29/2013

System Verilog for Verification



   
  TTĐT Thiết Kế Vi Mạch Semicon, Đào Tạo Kỹ Sư Vi Mạch ( IC Design) tương lai cho thế hệ trẻ Việt Nam
 


Website: http://www.vimachso.com
FanPage: System Verilog for Verification














 Semicon - Education With Trust



Đào Tạo System Verilog for Verification


Lớp Đào Tạo Ngôn Ngữ System Verilog cho Verification. Tập trung trong việc nghiên cứu ngôn ngữ System Verilog, Thiết kế lõi Môi Trường Mô Phỏng và xây dựng môi trường (randomization + Constraint cho randomization).

Bạn hãy nghĩ đền giải pháp làm thế nào để có thể xây dựng môi trường một cách nhanh nhất và dễ dàng thực hiện các mẩu tests random một cách dễ dàng nhất. Với SystemVerilog, ngôn ngữ lập trình hướng đối tượng (OOP) sẽ giúp bạn cải thiện được điều đó. 

✔ Đối tượng:
  • Các Anh/Chị sinh viên đã học Verilog
  • Anh/Chị đã học lớp cơ bản Verilog
  • Anh/Chị đang làm ở Công ty Chip, muốn học ngôn ngữ này để cải thiện công việc trong Công ty

✔ Thời gian đào tạo lớp cơ bản: (1,5 tháng)





System Verilog for Verification - Thiết Kế Vi Mạch Semicon 


Nguồn: http://vimachso.com

11/27/2013

Designing Hardware using Verilog


A Simple Design

A design is described in Verilog using the concept of a module. A module can be conceptualised as consisting of two parts, the port declarations and the module body. The port declarations represent the external interface to the module. The module body represents the internal description of the module - its behaviour, its structure, or a mixture of both. Let's imagine we want to describe an and-or-invert (AOI) gate in Verilog.



Verilog: an AOI gate module

// Verilog code for AND-OR-INVERT gate
module AOI (input A, B, C, D, output F);
  assign F = ~((A & B) | (C & D));
endmodule
// end of Verilog code

OK, that's the code. Let's dissect it line by line...

Comments


// Verilog code for AND-OR-INVERT gate

Like all programming languages, Verilog supports comments. There are two types of comment in Verilog, line comments and block comments; we will look at line comments for now. Comments are not part of the Verilog design, but allow the user to make notes referring to the Verilog code, usually as an aid to understanding it. Here the comment is a “header” that tells us that the Verilog describes an AOI gate. It is no more than an aide de memoire in this case. A Verilog compiler will ignore this line of Verilog. Two forward slashes mark the start of a line comment, which is ignored by the Verilog compiler. A line comment can be on a separate line or at the end of a line of Verilog code, but in any case stops at the end of the line.

Module and Port declarations

module AOI (input A, B, C, D, output F);

The name of the module is just an arbitrary label invented by the user. It does not correspond to a name pre-defined in a Verilog component library. module is a Verilog keyword. This line defines the start of a new Verilog module definition. All of the input and output ports of the module must appear in parentheses after the module name. The ordering of ports is not important for the module definition per se, although it is conventional to specify input ports first.

A port may correspond to a pin on an IC, an edge connector on a board, or any logical channel of communication with a block of hardware. The port declarations include the names of the ports ( e.g., A, B ), and the direction that information is allowed to flow through the ports (input, output or inout).

Endmodule

endmodule

The module definition is terminated by the Verilog keyword endmodule.

Functionality

Well, that's the interface to the module taken care of, but what about it's functionality?

assign F = ~((A & B) | (C & D));

In this module body, there is but one statement, and all the names referenced in this statement are in fact the ports of the design. Because all of the names used in the module body are declared in the module header and port declarations, there are no further declarations for internal elements required in the module body. assign is a Verilog keyword. It denotes a concurrent continuous assignment, which describes the functionality of the module. The concurrent assignment executes whenever one of the four ports A, B, C or D change value. The ~, & and | symbols represent the bit-wise not, and and or operators respectively, which are built in to the Verilog language. That's it! That's all there is to describing the functionality of an AOI gate in Verilog.

// end of Verilog code

Another Verilog comment, and that's the end of a Verilog description for an AOI gate.

Verilog 1995

The above example is written using Verilog-2001 syntax. Many people continue to use the 1995 syntax, which is still allowed in Verilog-2001. In Verilog-1995 the module header would look like this:

module AOI (A, B, C, D, F);
  input A, B, C, D;
  output F;

Note that the port names are listed after the module name, and declared as inputs and outputs in separate statements. The port declarations must repeat the names of the ports in the module header.

Wires

The module shown on the “Modules” page, was simple enough to describe using a continuous assignment where the output was a function of the inputs. Usually, modules are more complex than this, and internal connections are required. To make a continuous assignment to an internal signal, the signal must first be declared as a wire.

A Verilog wire represents an electrical connection.


Verilog: Internal signals of an AOI gate module

// Verilog code for AND-OR-INVERT gate
module AOI (input A, B, C, D, output F);
  wire F;  // the default
  wire AB, CD, O;  // necessary

  assign AB = A & B;
  assign CD = C & D;
  assign O = AB | CD;
  assign F = ~O;
endmodule
// end of Verilog code

OK, that's the code. Let's examine it a little more closely...

Wire Declarations

wire AB, CD, O;

This is the syntax for a wire declaration. A wire declaration looks like a Verilog-1995 style port declaration, with a type (wire), an optional vector width and a name or list of names. You can create separate wire declarations if you wish, for example:

wire AB, CD;
wire O;


is an alternative way of creating wire declarations.

Note that ports default to being wires, so the definition of wire F in the Verilog code is optional.

Continuous Assignments
assign AB = A & B;
assign CD = C & D;
assign O = AB | CD;
assign F = ~O;


In this module body, there are four continuous assignment statements. These statements are independent and executed concurrently. They are not necessarily executed in the order in which they are written. This does not affect the functionality of the design. Suppose assign AB = A & B; changes value. This causes B to be evaluated. If AB changes as a result then assign O = AB | CD; is evaluated. If O changes value then assign F = ~O; will be evaluated; possibly the output of the module will change due to a change on B.

Wire Assignments

A wire can be declared and continuously assigned in a single statement - a wire assignment. This is a shortcut which saves declaring and assigning a wire separately. There are no advantages or disadvantages between the two methods other than the obvious difference that wire assignments reduce the size the the text.

Later on we will discuss delays on assignments and wires. A delay in a wire assignment is equivalent to a delay in the corresponding continuous assignment, not a delay on the wire. Thus it could be necessary to separate the wire declaration from the continuous assignment to put the delay onto the wire rather than the assignment. Note that this is a subtle point that you are unlikely to encounter in practice!


Verilog: Using wire assignments to describe an AOI gate module

// Verilog code for AND-OR-INVERT gate
module AOI (input A, B, C, D, output F);
  /*  start of a block comment
  wire F;
  wire AB, CD, O;
  assign AB = A & B;
  assign CD = C & D;
  assign O = AB | CD;
  assign F = ~O;
  end of a block comment */

  // Equivalent...
  wire AB = A & B;
  wire CD = C & D;
  wire O = AB | CD;
  wire F = ~O;
endmodule
// end of Verilog code


So in this sample code, each of the wire declarations and its corresponding assign statement are effectively merged into one wire assignment.

Note the use of a block comment in the Verilog code, rather than the line comments we have seen so far. A block comment may span several lines of code. Block comments may not be nested.

A Design Hierarchy

Modules can reference other modules to form a hierarchy. Here we see a 2:1 multiplexer with an inverting data path consisting of an AOI gate and a pair of inverters.


Module Instances

The MUX_2 module contains references to each of the lower level modules, and describes the interconnections between them. In Verilog jargon, a reference to a lower level module is called a module instance.

Each instance is an independent, concurrently active copy of a module. Each module instance consists of the name of the module being instanced (e.g. AOI or INV), an instance name (unique to that instance within the current module) and a port connection list.

The module port connections can be given in order (positional mapping), or the ports can be explicitly named as they are connected (named mapping). Named mapping is usually preferred for long connection lists as it makes errors less likely.

Verilog: 2-input multiplexer module

// Verilog code for 2-input multiplexer
module INV (input A, output F);   // An inverter
  assign F = ~A;
endmodule

module AOI (input A, B, C, D, output F);
  assign F = ~((A & B) | (C & D));
endmodule

module MUX2 (input SEL, A, B, output F);   // 2:1 multiplexer
  // wires SELB and FB are implicit
  // Module instances...
  INV G1 (SEL, SELB);
  AOI G2 (SELB, A, SEL, B, FB);
  INV G3 (.A(FB), .F(F));            // Named mapping
endmodule
// end of Verilog code


Yes, it's time to dissect the code line by line again, but we'll concentrate on the new lines as the module interface has been covered before (see A Simple Design).

Implicit Wires

// wires SELB and FB are implicit

The wires used in continuous assignments MUST be declared. However, one-bit wires connecting component instances together do not need to be declared. Such wires are regarded as implicit wires. Note that implicit wires are only one bit wide, if a connection between two components is a bus, you must declare the bus as a wire.

Module Instances

AOI G2 (SELB, A, SEL, B, FB);
In a module instance, the ports defined in the module interface are connected to wires in the instantiating module through the use of port mapping. For the instance of AOI, the first wire in the port list is SELB. In the module header for the AOI gate, A is the first port in the port list, so SELB is connected to A. The second port in the module header is B, the second wire in the port list is A, thus the wire A in MUX2 is connecyted to the port B of the AOI gate instance.

INV G3 (.A(FB), .F(F));

The second INV instance, G3, uses named mapping rather than positional mapping. In the port list for the G£ instance, the wire FB is connected to the input port, A, of the INV instance. The period character is followed by the name of the module header port; in brackets following the formal port, the name of the wire is entered.

Test Benches

Test benches help you to verify that a design is correct. How do you create a simple testbench in Verilog?

verilog

Let's take the exisiting MUX_2 example module and create a testbench for it. We can create a template for the testbench code simply by refering to the diagram above.

module MUX2TEST;  // No ports!
  ...
  initial
  // Stimulus
  ...

  MUX2 M (SEL, A, B, F);

  initial
  // Analysis
  ...

endmodule


Initial Statement

In this code fragment, the stimulus and response capture are going to be coded using a pair of initial blocks. An initial block can contain sequential statements that can be used to describe the behaviour of signals in a test bench.

In the Stimulus initial block, we need to generate waveform on the A, B and SEL inputs. Thus:

initial  // Stimulus
begin
  SEL = 0; A = 0; B = 0;
  #10 A = 1;
  #10 SEL = 1;
  #10 B = 1;
end


Once again, let's look at each line in turn.

SEL = 0; A = 0; B = 0;

This line contains three sequential statements. First of all, SEL is set to 0, then A, then B. All three are set to 0 at simulation time 0.

#10 A = 1;
In terms of simulation, the simulator now advances by 10 time units and then assigns 1 to A. Note that we are at simulation time = 10 time units, not 10 ns or 10 ps! Unless we direct the Verilog simulator otherwise, a Verilog simulation works in dimensionless time units.

#10 SEL = 1;
#10 B = 1;


These two lines are similar to the one above. 10 time units after A is set to 1, SEL is set to 1. Another 10 time units later (so we are now at simulation time = 30 time units), B is set to 1. The diagram below shows how the initial block has created a waveform sequence for the three signals.


We shall look at the use of the initial block to capture the MUX_2's response in the next section of the tutorial.

Response Capture

In the previous section of the tutorial, we looked at describing stimuli in Verilog to test our 2-input multiplexer. So next, we’ll look at how to capture the response of our device under test.

verilog
Remember from the module template that we are using initial blocks to code up the Stimulus and Response blocks.

module MUX2TEST;  // No ports!
  ...
  initial
  // Stimulus

  ...

  MUX2 M (SEL, A, B, F);

  initial
  // Analysis
  ...

endmodule


The Response initial block can be described very easily in Verilog as we can benefit from a built-in Verilog system task. Thus:

initial  // Response
  $monitor($time, , SEL, A, B, F);


Once again, let's look at each item in turn.

$monitor();

$monitor is a system task that is part of the Verilog language. Its mission in life is to print values to the screen. The values it prints are those corresponding to the arguments that you pass to the task when it is executed. The $monitor task is executed whenever any one of its arguments changes, with one or two notable exceptions.

$time

$time is a system function (as opposed to a system task). It returns the current simulation time. In the above example, $time is an argument to $monitor. However, $time changing does not cause $monitor to execute - $monitor is clever enough to know that you wouldn't really want to print to the screen the values of all of the arguments every time the simulation time changed.

, , ,

The space at position 2 in the argument list ensures that a space is printed to the screen after the value of $time each time $monitor is executed. This is a simple method of formatting the screen output.

SEL, A, B, F


Finally we come to the signal arguments themselves. Each time one of these signals changes value, $monitor will execute. When $monitor executes it will print all of the argument values to the screen, including $time. This is the output created by $monitor in our MUX2 testbench:

 0 0000
10 0101
20 1100
30 1111


This is simply a tabular listing of the waveforms that would be generated during simulation (if we had a waveform viewer, that is!).

It's amazing what you can learn from two lines of code, isn't it? We'll look at more elaborate output formatting soon.

RTL Verilog

Remember this?

Verilog
Now we are going to look at the principles of RTL coding for synthesis tools.

Most commercially available synthesis tools expect to be given a design description in RTL form. RTL is an acronym for register transfer level. This implies that your Verilog code describes how data is transformed as it is passed from register to register. The transforming of the data is performed by the combinational logic that exists between the registers. Don't worry! RTL code also applies to pure combinational logic - you don't have to use registers. To show you what we mean by RTL code, let's consider a simple example.

module AOI (input A, B, C, D, output F);
  assign F = ~((A & B) | (C & D));
endmodule


Yes! The AOI gate that we have used as an example so far has actually been written in RTL form. This means that continuous assignments are a valid way of describing designs for input to RTL synthesis tools. What other code techniques can we use? How about:

module MUX2 (input SEL, A, B, output F);
  input SEL, A, B;
  output F;
  INV G1 (SEL, SELB);
  AOI G2 (SELB, A, SEL, B, FB);
  INV G3 (.A(FB), .F(F));
endmodule


Module instances are also examples of synthesizable RTL statements. However, one of the reasons to use synthesis technology is to be able to describe the design at a higher level of abstraction than using a collection of module instances or low-level binary operators in a continuous assignment. We would like to be able to describe what the design does and leave the consideration of how the design is implemented up to the synthesis tool. This is a first step (and a pretty big conceptual one) on the road to high-level design. We are going to use a feature of the Verilog language that allows us to specify the functionality of a design (the ‘what') that can be interpreted by a synthesis tool.

Always blocks

Always blocks are akin to the initial blocks that you have met already in Test Benches. Initial blocks are procedural blocks that contain sequential statements. Initial blocks execute just once. Always blocks on the other hand are always available for execution. This means that the statements inside an always block are executed up until the closing end keyword:

always
begin
  // statements
end

But then they can be executed again! This means that a way of controlling execution through an always block is required. In describing synthesizable designs, a sensitivity list is often used to control execution (we shall see other approaches later).

always @(sensitivity-list)
begin
  // statements
end


The sensitivity list consists of one or more signals. When at least one of these signals changes, the always block executes through to the end keyword as before. Except that now, the sensitivity list prevents the always block from executing again until another change occurs on a signal in the sensitivity list.

The statements inside the always block describe the functionality of the design (or a part of it). Let's reconsider the AOI gate:

always @(sensitivity-list)
begin
  F = ~((a & b) | (c & d));
end

Instead of a continuous assignment, we now have a procedural assignment to describe the functionality of the AOI gate. Notice that the sensitivity list isn't valid Verilog code. We need to create a meaningful sensitivity list. How do we decide when to execute the always block? Perhaps a better question is what do we need to do in order to have F change value. Answer: F can only change when at least one of a, b, c or d changes. After all, these are the four inputs to the AOI gate. That's our sensitivity list:

always @(a or b or c or d)
begin
  F = ~((a & b) | (c & d));
end


Verilog-2001 introduced additional syntax for describing sensitivity lists.

always @(a, b, c, d)

always @(*)

always @*


In the first of these, we have simply replaced the word or with a comma. The other two are equivalent and create an implicit sensitivity list that contains all the signals whose values are read in the statements of the always block. In this example @* or @(*) are equivalent to @(a,b,c,d). When describing combinational logic, it is important to make sure that sensitivity lists are complete; this syntax helps to ensure that this is holds.

Now for the MUX_2 design. In the above code snippet, we simply replaced the continuous assignment with an equivalent always block. We can do the same with the module instances in the MUX_2 design - strip away each instance and replace it with the equivalent always block.

always @(sel)
begin
  selb = ~sel;
end

always @(a or sel or b or selb)
begin
  fb = ~((a & sel) | (b & selb));
end

always @(fb)
begin
  f = ~fb;
end


But we can do better than this. Let's merge the three always blocks together remembering that in the process (a pun for the VHDL'ers amongst you!) the sensitivity list of the resulting one always block contains only those signals that cause F to change value.

always @(sel or a or b)
begin
  selb = ~sel;
  fb = ~((a & sel) | (b & selb));
  f = ~fb;
end


When writing RTL code, “think functionality, think inputs” is a useful aide memoire in terms of bridging the gap between concept and code. Well, we have already taken care of the inputs as the sensitivity list now consists of only the MUX_2 input ports.

For the functionality, let’s get conceptual. If sel is a logic 1, a is routed through to the f output. On the other hand if sel is a logic 0, b is routed through to the f output. Rather than think about routing one of the inputs through to the output let's think about the output getting one of the inputs, and let's write the text on separate lines depending upon whether we are making a decision or performing an action (sometimes referred to as pseudo-code):

if sel is logic 1
  f gets a
otherwise
  f gets b


This can be translated into Verilog code:

if (sel == 1)
  f = a;
else
  f = b;


Now before we go any further, we'll just take this code snippet a line at a time.

if (sel == 1)

The Verilog language allows for many different kinds of sequential statement. The procedural assignment is one you have already come across not only on this page but also in test benches (assignments to SEL, A and B in the stimulus initial block, if you remember). Here's another: the if statement. Actually this line is part of the if-else statement that is the entire code snippet. if is a Verilog keyword. After the if keyword you have a conditional expression, in this case (sel == 1) - does sel have the value logic 1? If so...

f = a;

f gets the value on the a input. Or in Verilog jargon, a procedural assignment. But what if sel is not logic 1?

else

Otherwise (assume sel is logic 0 - more on this assumption later)...

f = b;

f
gets the value on the b input.

So, as it turns out, we have described the funcionality of the MUX_2 design using a single procedural statement, the if-else statement. In each branch of this if-else statement, there is an additional procedural statement, either assigning a to f, or b to f, depending upon the value of sel. But we have to remember that this procedural statement lives inside an always block, so...

always @(sel or a or b)
begin
  if (sel == 1)
    f = a;
  else
    f = b;
end


This now enables us to describe a design using a list of continuous assignments, a hierarchy of designs or an always block. Compare the 3 approaches for yourself:

// continuous assignments
assign selb = ~sel;
assign fb = ~((a & sel) | (b & selb));
assign f = ~fb

// a hierarchy of designs
INV G1 (SEL, SELB);
AOI G2 (SELB, A, SEL, B, FB);
INV G3 (.A(FB), .F(F));

// always block
always @(sel or a or b)
begin
  if (sel == 1)
    f = a;
  else
    f = b;
end


And of course you can mix'n'match coding styles if you wish. On a simple design, such as a MUX_2 it is perhaps not apparent how succinct the use of always blocks is in general compared to module instances and continuous assignments. But you can readily appreciate that the use of just one always block in this design is enabling us to describe the design in terms of its functionality without regard to the implementation. You can describe what you want without having to worry about how you are going to implement the design (because you don't have to - that's the synthesis tool's job!).

Go on! Read the MUX_2 design into your synthesis tool and have a play.


If statement

In the last section, we looked at describing hardware conceptually using always blocks. What kind of hardware can we describe? What are the limitations? What kinds of Verilog statement can be used in always blocks to describe hardware? Well, we have already seen the use of an if statement to describe a multiplexer, so let's dwell on if statements in this section.

always @(sensitivity-list) // invalid Verilog code!
begin
// statements
end


The code snippet above outlines a way to describe combinational logic using always blocks. To model a multiplexer, an if statement was used to describe the functionality. In addition, all of the inputs to the multiplexer were specified in the sensitivity list.

reg f;
always @(sel or a or b)
begin
  if (sel == 1)
    f = a;
  else
    f = b;
end


Variable declaration

It is a fundamental rule of the Verilog HDL that any object that is assigned a value in an always statement must be declared as a variable. Hence,

reg f; // must be declared before it is used in a statement
The term variable was introduced in the verilog-2001 standard. Previously, the term used was register. This was confusing, because a Verilog variable (register) does not necessarily imply that a hardware register would be synthesised. hence the change of terminology.

Combinational logic

It transpires that in order to create Verilog code that can be input to a synthesis tool for the synthesis of combinational logic, the requirement for all inputs to the hardware to appear in the sensitivity list is a golden rule.

    Golden Rule 1:


    To synthesize combinational logic using an always block, all inputs to the design must appear in the sensitivity list.

Altogether there are 3 golden rules for synthesizing combinational logic, we will address each of these golden rules over the next couple of sections in this tutorial.
 
If statement

The if statement in Verilog is a sequential statement that conditionally executes other sequential statements, depending upon the value of some condition. An if statement may optionally contain an else part, executed if the condition is false. Although the else part is optional, for the time being, we will code up if statements with a corresponding else rather than simple if statements. In order to have more than one sequential statement executed in an if statement, multiple statements are bracketed together using the begin..end keywords,

reg f, g; // a new reg variable, g
always @(sel or a or b)
begin
  if (sel == 1)
    begin
      f = a;
     g = ~a;
    end
  else
    begin
      f = b;
      g = a & b;
    end
end


If statements can be nested if you have more complex behaviour to describe:

reg f, g;
always @(sel or sel_2 or a or b)
  if (sel == 1)
    begin
      f = a;
      if (sel_2 == 1)
        g = ~a;
      else
        g = ~b;
    end
  else
    begin
      f = b;
      if (sel_2 == 1)
        g = a & b;
      else
        g = a | b;
    end


Notice that the code is beginning to look a little bit confusing! In the code above, begin..end blocks have only been used where they must be used, that is, where we have multiple statements. It is probably a good idea to use begin..end blocks throughout your Verilog code - you end up typing in a bit more Verilog but it's easier to read. Also, if you have to add more functionality to an always block later on (more sequential statement), at least the begin..end block is already in place. So,

reg f, g, h; // yes, an extra reg variable, h
always @(sel or sel_2 or a or b)
  begin
    if (sel == 1)
    begin
      f = a;
      if (sel_2 == 1)
        begin
          h = ~b;
          g = ~a;
        end
    else
      begin
        g = a | b;
        h = a & b;
      end
  end
else
  begin
    if (sel_2 == 1)
      begin
        g = a & b;
        h = ~(a & b);
      end
    else
      begin
        h = ~(a | b);
        g = a | b;
      end
      f = b;  // here's f!
  end
end


Note that the order of assignments to f, g and h has been played around with (just to keep you on your toes!).

Synthesis considerations

If statements are synthesized by generating a multiplexer for each variable assigned within the if statement. The select input on each mux is driven by logic determined by the if condition, and the data inputs are determined by the expressions on the right hand sides of the assignments. During subsequent optimization by a synthesis tool, the multiplexer architecture may be changed to a structure using and-or-invert gates as surrounding functionality such as the a & b and the ~a can be merged into complex and-or-invert gates to yield a more compact hardware implementation.

Synthesizing Latches

In the last section, if statements were used to describe simple combinational logic circuits. Synthesizing the Verilog code produced multiplexing circuits, although the exact implementation depends upon the synthesis tool used and the target architecture of the device.

As well as enabling the creation of multiplexers, if statements can also be used to implement tristate buffers and transparent latches. In this article we will look at how transparent latches are synthesized from if statements and how to avoid the inadvertent creation of latches when you meant to create combinational logic circuits from Verilog code containing if statements.

If Statements

In the processes that have been coded up so far, if-else statements rather than simple if statements have been used. Let's use a simple if statement rather than an if-else statement in an example you have already seen:

reg sel, a, b;

always @ (sel or a or b)
  begin : if_else
    if (sel == 1)
      f = a;
    else
      f = b;
  end

becomes...
reg sel, a, b;

always @ (sel or a or b)
  begin : pure_if
    f = b;
    if (sel == 1)
      f = a;
  end

Note that the behaviour being described is the same. In the pure_if always block, f initially gets b. Only if sel is active HIGH does f get a. This is perhaps a slightly odd way to describe a multiplexing circuit but it is accepted by all synthesis tools. Synthesis tools expect to create circuits responding to binary values. As far as a synthesis tool is concerned if sel is 1 a is routed through to f. If sel is not 1 it must be 0 and thus sel being 0 leaves f being driven by the initial assignment from b.

Let's lose the b input to the always block so that we have:

reg sel, a;

always @ (sel, a)
  begin : latching_if
    if (sel == 1)
      f = a;
  end

Incomplete Assignment

Now analyze the behaviour of the code. If sel is 1, f gets a. But what happens when sel is 0? Well, very simply, nothing! f does not and can not change. When sel is fixed at 0, we can change a as much as we like, f will not be assigned the value of a. If we suppose that an if statement synthesises to a multiplexer, then we must be able to configure the multiplexer such that f only gets the value of a when sel is 1. This can be achieved by feeding back the multiplexer f output back to the 0 input; in hardware terms this is a transparent latch and this is exactly the hardware synthesized by a synthesis tool given this Verilog code.


If the target architecture does not contain transparent latches the synthesis tool will generate multiplexer circuits that employ combinational feedback in order to mimic the latching behaviour required.

Now, this is very well but what's really happening here? One minute if statements create multiplexers, the next they create latches. Well, it's not the if statements, but the process as a whole that counts. If it is possible to execute an always block without assigning a value to a signal in that always block, the reg variable will be implemented as a transparent latch. This is known as incomplete assignment.

    Golden Rule 2:
    To synthesize combinational logic using an always block, all variables must be assigned under all conditions.


Simplifying code analysis

Suppose you are creating an always block to describe combinational logic. This always block consists of nested if-else statements as follows:

reg f, g;
always @ (sel or sel_2 or sel_3 or a or b)
  begin
    if (sel == 1)
      begin
        f = a;
        if (sel_2 == 1)
          g = ~ a;
        else
          begin
            g = ~ b;
            if (sel_3 == 1)
              g = a ^ b;
          end
      end
    else
      begin
        if (sel_2 == 1)
          g = a & b;
        else
          if (sel_3 == 1)
            g = ~(a & b);
          // oops! no else
          // else
          //   g = ...
          f = b;
      end
  end


Will you get transparent latches on the f and g outputs? Not easy is it? If you look carefully you will see that in fact, g is latched when sel is 0, sel_2 is 0 and sel_3 is 0. The ‘oops!' comment should help you to see where the complete assignment is NOT made.
 
Default Assignment
Fortunately, it is possible to save yourself the bother of scouring through the always block code to locate possible incomplete assignments by setting variables to default values at the start of the always block. Using this approach you may get undesired functionality if you have missed out an assignment (which should be easy to fix) as opposed to unwanted transparent latches. For our current example,

always @ (sel or sel_2 or sel_3 or a or b)
  begin
    // default values assigned to f, g
    f = b;
    g = a & b;
    if (sel == 1)
      begin
        f = a;
        if (sel_2 == 1)
          g = ~ a;
       else
         begin
           g = ~ b;
           if (sel_3 == 1)
             g = a ^ b;
         end
      end
    else
      if (sel_2 == 1)
        g = a & b;
      else
        if (sel_3 == 1)
          g = ~(a & b);
  end


Nguồn doulos

11/25/2013

Verilog interview Questions & answers for FPGA & ASIC.


 Verilog interview Questions (1)

1) Write a verilog code to swap contents of two registers with and without a temporary register?

With temp reg ;

always @ (posedge clock)
begin
temp=b;
b=a;
a=temp;
end

Without temp reg;

always @ (posedge clock)
begin
a <= b;
b <= a;
end

Click to view more


2) Difference between blocking and non-blocking?(Verilog interview questions that is most commonly asked)

The Verilog language has two forms of the procedural assignment statement: blocking and non-blocking. The two are distinguished by the = and <= assignment operators. The blocking assignment statement (= operator) acts much like in traditional programming languages. The whole statement is done before control passes on to the next statement. The non-blocking (<= operator) evaluates all the right-hand sides for the current time unit and assigns the left-hand sides at the end of the time unit. For example, the following Verilog program

// testing blocking and non-blocking assignment

module blocking;
reg [0:7] A, B;
initial begin: init1
A = 3;
#1 A = A + 1; // blocking procedural assignment
B = A + 1;

$display("Blocking: A= %b B= %b", A, B ); A = 3;
#1 A <= A + 1; // non-blocking procedural assignment
B <= A + 1;
#1 $display("Non-blocking: A= %b B= %b", A, B );
end
endmodule

produces the following output:
Blocking: A= 00000100 B= 00000101
Non-blocking: A= 00000100 B= 00000100

The effect is for all the non-blocking assignments to use the old values of the variables at the beginning of the current time unit and to assign the registers new values at the end of the current time unit. This reflects how register transfers occur in some hardware systems.
blocking procedural assignment is used for combinational logic and non-blocking procedural assignment for sequential

Click to view more


Tell me about verilog file I/O?

OPEN A FILE

integer file;
file = $fopenr("filename");
file = $fopenw("filename");
file = $fopena("filename");
The function $fopenr opens an existing file for reading. $fopenw opens a new file for writing, and $fopena opens a new file for writing where any data will be appended to the end of the file. The file name can be either a quoted string or a reg holding the file name. If the file was successfully opened, it returns an integer containing the file number (1..MAX_FILES) or NULL (0) if there was an error. Note that these functions are not the same as the built-in system function $fopen which opens a file for writing by $fdisplay. The files are opened in C with 'rb', 'wb', and 'ab' which allows reading and writing binary data on the PC. The 'b' is ignored on Unix.

CLOSE A FILE

integer file, r;
r = $fcloser(file);
r = $fclosew(file);

The function $fcloser closes a file for input. $fclosew closes a file for output. It returns EOF if there was an error, otherwise 0. Note that these are not the same as $fclose which closes files for writing.

Click to view more


3) Difference between task and function?


Function:
A function is unable to enable a task however functions can enable other functions.
A function will carry out its required duty in zero simulation time. ( The program time will not be incremented during the function routine)
Within a function, no event, delay or timing control statements are permitted
In the invocation of a function their must be at least one argument to be passed.
Functions will only return a single value and can not use either output or inout statements.


Tasks:
Tasks are capable of enabling a function as well as enabling other versions of a Task
Tasks also run with a zero simulation however they can if required be executed in a non zero simulation time.
Tasks are allowed to contain any of these statements.
A task is allowed to use zero or more arguments which are of type output, input or inout.
A Task is unable to return a value but has the facility to pass multiple values via the output and inout statements .

4) Difference between inter statement and intra statement delay?

//define register variables
reg a, b, c;

//intra assignment delays
initial
begin
a = 0; c = 0;
b = #5 a + c; //Take value of a and c at the time=0, evaluate
//a + c and then wait 5 time units to assign value
//to b.
end

//Equivalent method with temporary variables and regular delay control
initial
begin
a = 0; c = 0;
temp_ac = a + c;
#5 b = temp_ac; //Take value of a + c at the current time and
//store it in a temporary variable. Even though a and c
//might change between 0 and 5,
//the value assigned to b at time 5 is unaffected.
end


5) What is delta simulation time?

6) Difference between $monitor,$display & $strobe?


These commands have the same syntax, and display text on the screen during simulation. They are much less convenient than waveform display tools like cwaves?. $display and $strobe display once every time they are executed, whereas $monitor displays every time one of its parameters changes.
The difference between $display and $strobe is that $strobe displays the parameters at the very end of the current simulation time unit rather than exactly where it is executed. The format string is like that in C/C++, and may contain format characters. Format characters include %d (decimal), %h (hexadecimal), %b (binary), %c (character), %s (string) and %t (time), %m (hierarchy level). %5d, %5b etc. would give exactly 5 spaces for the number instead of the space needed. Append b, h, o to the task name to change default format to binary, octal or hexadecimal.
Syntax:
$display (“format_string”, par_1, par_2, ... );
$strobe (“format_string”, par_1, par_2, ... );
$monitor (“format_string”, par_1, par_2, ... );


7) What is difference between Verilog full case and parallel case?

A "full" case statement is a case statement in which all possible case-expression binary patterns can be matched to a case item or to a case default. If a case statement does not include a case default and if it is possible to find a binary case expression that does not match any of the defined case items, the case statement is not "full."
A "parallel" case statement is a case statement in which it is only possible to match a case expression to one and only one case item. If it is possible to find a case expression that would match more than one case item, the matching case items are called "overlapping" case items and the case statement is not "parallel."

8) What is meant by inferring latches,how to avoid it?

Consider the following :
always @(s1 or s0 or i0 or i1 or i2 or i3)
case ({s1, s0})
2'd0 : out = i0;
2'd1 : out = i1;
2'd2 : out = i2;
endcase

in a case statement if all the possible combinations are not compared and default is also not specified like in example above a latch will be inferred ,a latch is inferred because to reproduce the previous value when unknown branch is specified.
For example in above case if {s1,s0}=3 , the previous stored value is reproduced for this storing a latch is inferred.
The same may be observed in IF statement in case an ELSE IF is not specified.
To avoid inferring latches make sure that all the cases are mentioned if not default condition is provided.

9) Tell me how blocking and non blocking statements get executed?

Execution of blocking assignments can be viewed as a one-step process:
1. Evaluate the RHS (right-hand side equation) and update the LHS (left-hand side expression) of the blocking assignment without interruption from any other Verilog statement. A blocking assignment "blocks" trailing assignments in the same always block from occurring until after the current assignment has been completed

Execution of nonblocking assignments can be viewed as a two-step process:
1. Evaluate the RHS of nonblocking statements at the beginning of the time step. 2. Update the LHS of nonblocking statements at the end of the time step.

10) Variable and signal which will be Updated first?

Signals

11) What is sensitivity list?

The sensitivity list indicates that when a change occurs to any one of elements in the list change, begin…end statement inside that always block will get executed.

12) In a pure combinational circuit is it necessary to mention all the inputs in sensitivity disk? if yes, why?

Yes in a pure combinational circuit is it necessary to mention all the inputs in sensitivity disk other wise it will result in pre and post synthesis mismatch.

13) Tell me structure of Verilog code you follow?

A good template for your Verilog file is shown below.

// timescale directive tells the simulator the base units and precision of the simulation
`timescale 1 ns / 10 ps
module name (input and outputs);
// parameter declarations
parameter parameter_name = parameter value;
// Input output declarations
input in1;
input in2; // single bit inputs
output [msb:lsb] out; // a bus output
// internal signal register type declaration - register types (only assigned within always statements). reg register variable 1;
reg [msb:lsb] register variable 2;
// internal signal. net type declaration - (only assigned outside always statements) wire net variable 1;
// hierarchy - instantiating another module
reference name instance name (
.pin1 (net1),
.pin2 (net2),
.
.pinn (netn)
);
// synchronous procedures
always @ (posedge clock)
begin
.
end
// combinatinal procedures
always @ (signal1 or signal2 or signal3)
begin
.
end
assign net variable = combinational logic;
endmodule

14) Difference between Verilog and vhdl?

Compilation
VHDL. Multiple design-units (entity/architecture pairs), that reside in the same system file, may be separately compiled if so desired. However, it is good design practice to keep each design unit in it's own system file in which case separate compilation should not be an issue.


Verilog. The Verilog language is still rooted in it's native interpretative mode. Compilation is a means of speeding up simulation, but has not changed the original nature of the language. As a result care must be taken with both the compilation order of code written in a single file and the compilation order of multiple files. Simulation results can change by simply changing the order of compilation.


Data types
VHDL. A multitude of language or user defined data types can be used. This may mean dedicated conversion functions are needed to convert objects from one type to another. The choice of which data types to use should be considered wisely, especially enumerated (abstract) data types. This will make models easier to write, clearer to read and avoid unnecessary conversion functions that can clutter the code. VHDL may be preferred because it allows a multitude of language or user defined data types to be used.

Verilog. Compared to VHDL, Verilog data types a re very simple, easy to use and very much geared towards modeling hardware structure as opposed to abstract hardware modeling. Unlike VHDL, all data types used in a Verilog model are defined by the Verilog language and not by the user. There are net data types, for example wire, and a register data type called reg. A model with a signal whose type is one of the net data types has a corresponding electrical wire in the implied modeled circuit. Objects, that is signals, of type reg hold their value over simulation delta cycles and should not be confused with the modeling of a hardware register. Verilog may be preferred because of it's simplicity.

Design reusability
VHDL. Procedures and functions may be placed in a package so that they are avail able to any design-unit that wishes to use them.

Verilog. There is no concept of packages in Verilog. Functions and procedures used within a model must be defined in the module. To make functions and procedures generally accessible from different module statements the functions and procedures must be placed in a separate system file and included using the `include compiler directive.

15) What are different styles of Verilog coding I mean gate-level,continuous level and others explain in detail?

16) Can you tell me some of system tasks and their purpose?


$display, $displayb, $displayh, $displayo, $write, $writeb, $writeh, $writeo.
The most useful of these is $display.This can be used for displaying strings, expression or values of variables.
Here are some examples of usage.
$display("Hello oni");
--- output: Hello oni
$display($time) // current simulation time.
--- output: 460
counter = 4'b10;
$display(" The count is %b", counter);
--- output: The count is 0010
$reset resets the simulation back to time 0; $stop halts the simulator and puts it in interactive mode where the
user can enter commands; $finish exits the simulator back to the operating system


17) Can you list out some of enhancements in Verilog 2001?

In earlier version of Verilog ,we use 'or' to specify more than one element in sensitivity list . In Verilog 2001, we can use comma as shown in the example below.
// Verilog 2k example for usage of comma
always @ (i1,i2,i3,i4)

Verilog 2001 allows us to use star in sensitive list instead of listing all the variables in RHS of combo logics . This removes typo mistakes and thus avoids simulation and synthesis mismatches,
Verilog 2001 allows port direction and data type in the port list of modules as shown in the example below
module memory (
input r,
input wr,
input [7:0] data_in,
input [3:0] addr,
output [7:0] data_out
);


18)Write a Verilog code for synchronous and asynchronous reset?

Synchronous reset, synchronous means clock dependent so reset must not be present in sensitivity disk eg:
always @ (posedge clk )

begin if (reset)
. . . end
Asynchronous means clock independent so reset must be present in sensitivity list.
Eg
Always @(posedge clock or posedge reset)
begin
if (reset)
. . . end

19) What is pli?why is it used?

Programming Language Interface (PLI) of Verilog HDL is a mechanism to interface Verilog programs with programs written in C language. It also provides mechanism to access internal databases of the simulator from the C program.
PLI is used for implementing system calls which would have been hard to do otherwise (or impossible) using Verilog syntax. Or, in other words, you can take advantage of both the paradigms - parallel and hardware related features of Verilog and sequential flow of C - using PLI.

20) There is a triangle and on it there are 3 ants one on each corner and are free to move along sides of triangle what is probability that they will collide?


Ants can move only along edges of triangle in either of direction, let’s say one is represented by 1 and another by 0, since there are 3 sides eight combinations are possible, when all ants are going in same direction they won’t collide that is 111 or 000 so probability of not collision is 2/8=1/4 or collision probability is 6/8=3/4


Theo asic.co

11/20/2013

Typical Verification Flow


../images/main/bullet_green_ball.gif Verification Flow With Specman

Verification flow with specman is the same as with any other HVL. The figure below shows the verification flow with specman.

Verification Flow

Verification flow starts with understanding the specification of the chip/block under verification. Once the specification is understood, a test cases document is prepared, which documents all possible test cases. Once this document is done to a level where 70-80 percent functionality is covered, a testbench architecture document is prepared. In the past, this document was prepared first and the test cases one was prepared next. There is a drawback with this style: if test cases document shows a particular functionality to be verified and if testbench does not support it, as the architecture document was prepared before the test cases one. If we have a test cases document to refer to, then writing an architecture document becomes much easier, as we know for sure what is expected from the testbench.       

Note:
This section was written in a hurry, so it is very far from what I really want it to be!!!


../images/main/bulllet_4dots_orange.gif Test Cases

 Identify the test cases from the design specification: a simple task for simple cases. Normally requirement in test cases becomes a test case. Anything that specification mentions with "Can do", "will have" becomes a test case. Corner test cases normally take lot of thinking to be identified.

../images/main/bulllet_4dots_orange.gif Testbench Architecture

  Typical testbench architecture looks as shown below. The main blocks in a testbench are base object, transaction generator, driver, monitor, checker/scoreboard.


The block in red is the DUT, and boxes in orange are the testbench components. Coverage is a separate block which gets events from the input and output monitors. It is the same as the scoreboard, but does something more.

../images/main/bullet_star_pink.gif Base Object

 Base object is the data structure that will be used across the testbench. Let's assume you are verifying a memory, then the base object would contain:
       
  1 <'
  2 struct mem_object {
  3   addr    : uint (bits:8);
  4   data    : uint (bits:8);
  5   rd_wt   : uint [0..100];
  6   wr_wt   : uint [0..100];
  7   rd_wr   : bool;
  8   keep soft rd_wt == 50;
  9   keep soft wr_wt == 50;

10 
11   keep gen (wr_wt) before (rd_wr);
12   keep gen (rd_wt) before (rd_wr);
13   // Default operation is Write
14   keep soft rd_wr == FALSE;
15 
16   keep soft rd_wr == select {
17      rd_wt : TRUE;
18      wr_wt : FALSE;
19   };
20 };
21 '>

Here base_object is the name of the base object, in the same way as we have a module name for each module in Verilog or an entity name in VHDL. Address, data, read, write are various field of the base_object. Normally we have some default constraints and some methods (functions) which could manipulate the objects in the base object.

../images/main/bullet_star_pink.gif Transaction Generator

 Transaction generator generates the transactions based on the test constraints. Normally the transaction generator applies test case constraints on the base object and generate a base object based on constraints. Once generated, the transaction generator passes it to the driver.
         
A typical transaction generator would be like this:
     
  1 <'
  2 struct mem_txgen {
  3    ! mem_base : mem_object;
  4   //driver   : mem_driver;
  5    ! num_cmds : uint;
  6   // This method generates the commands and
  7   // calls the driver
  8   genrate_cmds()@sys.any is {
  9     for {var i:uint = 0 ; i < num_cmds; i+=1} do {

10       // Generate a write access
11       gen mem_base keeping {
12         it.addr == 0x10;
13     it.data == 0x22;
14     it.rd_wr == FALSE;
15       };
16       // call the driver
17       //driver.drive_object(mem_base);
18     };
19   };
20 };
21 '>

../images/main/bullet_star_pink.gif Driver

 Driver drives the base object generated by the transaction generator to the DUT. To do this, it implements the DUT input protocol. Something like this.    

  1 <'
  2 unit mem_driver {
  3   event clk is rise('top.mem_clk') @sim;
  4   // This method drives the DUT
  5   drive_mem(mem_base : mem_object)@clk is {
  6     wait cycle;
  7     //Driver ce,addr,rd_wr command
  8     'top.mem_ce' = 1;
  9     'top.mem_addr' = mem_base.addr;

10     'top.mem_rd_wr' = mem_base.rd_wr;
11     if (mem_base.rd_wr == FALSE) {
12       'top.mem_wr_data' = mem_base.data;
13     };
14     // Deassert all the driven signals
15     wait cycle;
16     'top.mem_ce' = 0;
17     'top.mem_addr' = 0;
18     'top.mem_rd_wr' = 0;
19     'top.mem_wr_data' = 0;
20   };
21 };
22 '>

../images/main/bullet_star_pink.gif Input Monitor

Input monitor monitors the input signals to the DUT. Example: in an ethernet switch, each ingoing packet is picked by the input monitor and passed to the checker.

../images/main/bullet_star_pink.gif Output Monitor

Output monitor monitors the output signals from DUT. Example: in an ethernet switch, each outgoing packet from the switch is picked by the output monitor and passed to the checker.

../images/main/bullet_star_pink.gif Checker/Scoreboard

Checker or Scoreboard basically checks if the output coming out of the DUT is correct or wrong. Basically scoreboards in e language are implemented using keyed lists.

../images/main/bulllet_4dots_orange.gif TestBench Coding
 
  Testbench coding starts after the testbench architecture document is complete, typically we start with:
  •     base object
  •     transaction generator
  •     driver
  •     input monitor
  •     output monitor
  •     scoreboard
If the project is big, all the tasks can start at the same time, as many engineers will be working on them.

../images/main/bulllet_4dots_orange.gif Test Case Execution

In this phase, test execution teams execute the test cases based on a priority. Typically once the focused test cases pass and some level of random test cases pass, we move to regression. In regression all the test cases are run with different seeds every time there is change in RTL.

../images/main/bulllet_4dots_orange.gif Post Processing    
 
In post processing, code and functional coverage is checked to see if all the possible DUT functionality is covered.

../images/main/bullet_green_ball.gif Code Coverage

Code coverage shows which part of the RTL is tested, thus is used as a measurement to show how well the DUT is verified. Also code coverage shows how good the functional coverage matrix is.
          
There are many types of code coverage as listed below:
  •     Line Coverage
  •     Branch Coverage
  •     Expression Coverage
  •     Toggle Coverage
  •     FSM Coverage


../images/main/bulllet_4dots_orange.gif Line Coverage

    Line coverage or block coverage or segment coverage shows how many times each line is executed.

../images/main/bulllet_4dots_orange.gif Branch Coverage

    Branch coverage shows if all the possible branches of if..else or case statements are reached or not.

../images/main/bulllet_4dots_orange.gif Expression Coverage
 
    The golden of all coverage types. Expression coverage shows if all possible legal boolean values of an expression are reached or not. Generally expression coverage of 95% and above for large design is considered good.

../images/main/bulllet_4dots_orange.gif Toggle Coverage
         Toggle coverage shows which bits in the RTL have toggled. Toggle coverage is used for power analysis mainly.

../images/main/bulllet_4dots_orange.gif FSM Coverage   
   The FSM coverage shows if all states are reached, if all possible state transitions have happened.       


Theo asic-world