Signal Aliasing

The Verilog assign statement is a unidirectional assignment and can incorporate a delay and strength change.

To model a bidirectional short-circuit connection it is necessary to use the alias statement. The members of an alias list are signals whose bits share the same physical nets. The example below implements a byte-order swapping between bus A and bus B.

module byte_swap (inout wire [31:0] A, inout wire [31:0] B);
   alias {A[7:0],A[15:8],A[23:16],A[31:24]} = B;
endmodule

This example strips out the least and most significant bytes from a four-byte bus:

module byte_rip (inout wire [31:0] W, inout wire [7:0] LSB, MSB);
   alias W[7:0] = LSB;
   alias W[31:24] = MSB;
endmodule

The bit overlay rules are the same as those for a packed union with the same member types: each member shall be the same size, and connectivity is independent of the simulation host. The nets connected with an alias statement must be type compatible, that is, they have to be of the same net type. For example, it is illegal to connect a wand net to a wor net with an alias statement. This is a stricter rule than applied to nets joining at ports because the scope of an alias is limited and such connections are more likely to be a design error. Variables and hierarchical references cannot be used in alias statements. Any violation of these rules shall be considered a fatal error.

The same nets can appear in multiple alias statements. The effects are cumulative. The following two examples are equivalent. In either case, low12[11:4] and high12[7:0] share the same wires.

module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16[11:0] = low12;
alias bus16[15:4] = high12;
endmodule
module overlap(inout wire [15:0] bus16, inout wire [11:0] low12, high12);
alias bus16 = {high12, low12[3:0]};
alias high12[7:0] = low12[11:4];
endmodule

To avoid errors in the specification, it is not allowed to specify an alias from an individual signal to itself or to specify a given alias more than once. The following version of the code above would be illegal since the top four and bottom four bits are the same in both statements:

alias bus16 = {high12[11:8], low12};
alias bus16 = {high12, low12[3:0]};

This alternative is also illegal because the bits of bus16 are being aliased to itself:

alias bus16 = {high12, bus16[3:0]} = {bus16[15:12], low12};

Alias statements can appear anywhere in module instance statements, If an identifier that has not been declared as a data type appears in an alias statement, then an implicit net is assumed, following the same rules as implicit nets for a module instance. The following example uses an alias along with the automatic name binding to connect pins on cells from different libraries to create a standard macro:

module lib1_dff(Reset, Clk, Data, Q, Q_Bar);
...
endmodule

module lib2_dff(reset, clock, data, a, qbar);
...
endmodule

module lib3_dff(RST, CLK, D, Q, Q_);
...
endmodule

macromodule my_dff(rst, clk, d, q, q_bar); // wrapper cell
input rst, clk, d;
output q, q_bar;
alias rst = Reset = reset = RST;
alias clk = Clk = clock = CLK;
alias d = data = D;
alias q = Q;
alias Q_ = q_bar = Q_Bar = qbar;
‘LIB_DFF my_dff (.*); // LIB_DFF is any of lib1_dff, lib2_dff or lib3_dff
endmodule

<< Previous | Next >>

Data Declarations

There are several forms of data in SystemVerilog: literals, parameters, constants, variables, nets, and attributes
Constants are literals, genvars parameters, localparams, and specparams.
Variables must be written by procedural statements, and nets must be written by continuous assignments or ports.
SystemVerilog extends the functionality of variables by allowing them to either be written by procedural statements or driven by a single continuous assignment, similar to a wire. Since the keyword reg no longer describes the user’s intent in many cases, the keyword logic is added as a more accurate description that is equivalent to reg.

SystemVerilog requires data to be declared before it is used, apart from implicit nets. The rules for implicit nets are the same as in Verilog-2001.

A variable can be static (storage allocated on instantiation and never de-allocated) or automatic (stack storage allocated on entry to a scope (such as a task, function or block) and de-allocated on exit). SystemVerilog follows Verilog with respect of the static default storage class, with automatic tasks and functions, but allows static to override a default of automatic for a particular variable in such tasks and functions.

Constants

Constants are named data variables that never change. There are three kinds of constants, declared with the keywords localparam, specparam, and const.

localparam byte colon1 = ":" ;
specparam int delay = 10 ; // specparams are used for specify blocks
const logic flag = 1 ;

A parameter or local parameter can only be set to an expression of literals, parameters or local parameters, genvars, enumerated names, or a constant function of these. Hierarchical names are not allowed.
A specparam can also be set to an expression containing one or more specparams.

A static constant declared with the const keyword can only be set to an expression of literals, parameters, local parameters, genvars, enumerated names, a constant function of these, or other constants. The parameters, local parameters or constant functions can have hierarchical names because constants declared with the const keyword are calculated after elaboration. An automatic constant declared with the const keyword can be set to any expression that would be legal without the const keyword.

const logic option = a.b.c ;

A constant expression contains literals and other named constants.
An instance of a class (an object handle) can also be declared with the const keyword.

const class_name object = new(5,3);

This means that the object acts like a variable that cannot be written. The arguments to the new method must be constant expressions. The members of the object can be written (except for those members that are declared const).

SystemVerilog enhancements to parameter and localparam constant declarations. SystemVerilog does not change specparam constants declarations. A const form of constant differs from a localparam constant in that the localparam must be set during elaboration, whereas a const can be set during simulation, such as in an automatic task.

Variables

A variable declaration consists of a data type followed by one or more instances.

shortint s1, s2[0:9];

A variable can be declared with an initializer, for example:

int i = 0;

In Verilog-2001, an initialization value specified as part of the declaration is executed as if the assignment were made from an initial block after the simulation has started. Therefore, the initialization can cause an event on that variable at simulation time zero.

In SystemVerilog, setting the initial value of a static variable as part of the variable declaration (including static class members) shall occur before any initial or always blocks are started, and so does not generate an event. If an event is needed, an initial block should be used to assign the initial values.

Initial values in SystemVerilog are not constrained to simple constants; they can include run-time expressions, including dynamic memory allocation. For example, a static class handle or a mailbox can be created and initialized by calling its new method, or static variables can be initialized to random values by calling the $urandom system task. This requires a special pre-initial pass at run-time.

The default values for SystemVerilog variables are:

4 state integral:   ’x
2 state integral:   ’0
real, shortreal:     0.0
Enumeration:      First value in the enumeration
string:        “” (empty string)
event:         New event
class:       Null

Scope and lifetime

Any data declared outside a module, interface, task, or function, is global in scope (can be used anywhere after its declaration) and has a static lifetime (exists for the whole elaboration and simulation time).

SystemVerilog data declared inside a module or interface but outside a task, process or function is local in scope and static lifetime (exists for the lifetime of the module or interface).

Data declared in an automatic task, function, or block has the lifetime of the call or activation and a local scope.

Data declared in a static task, function, or block defaults to a static lifetime and a local scope.

Verilog-2001 allows tasks and functions to be declared as automatic, making all storage within the task or function automatic. SystemVerilog allows specific data within a static task or function to be explicitly declared as automatic. Data declared as automatic has the lifetime of the call or block, and is initialized on each entry to the call or block. The lifetime of a forkjoin, forkjoin_any, or forkjoin_none block shall encompass the execution of all processes spawned by the block. The lifetime of a scope enclosing any forkjoin block includes the lifetime of the forkjoin block.

SystemVerilog also allows data to be explicitly declared as static. Data declared to be static in an automatic task, function or block has a static lifetime and a scope local to the block.

module msl;
int st0; // static
initial begin
int st1; //static
static int st2; //static
automatic int auto1; //Automatic
end
task automatic t1();
int auto2; //Automatic
static int st3; //static
automatic int auto3; //Automatic
endtask
endmodule

SystemVerilog adds an optional qualifier to specify the default lifetime of all variables declared in a task, function, or block defined within a module, interface, or program. The lifetime qualifier is automatic or static. The default lifetime is static.

program automatic test ;
int i; // not within a procedural block - static
task foo( int a ); // arguments and variables in foo are automatic
$display("%0d",a);
endtask
endmodule

Class methods and declared for loop variables are by default automatic, regardless of the lifetime attribute of the scope in which they are declared.
Note that automatic or dynamic variables cannot be written with nonblocking or continuous assignments.
Automatic variables and dynamic constructs—object handles, dynamic arrays, associative arrays, strings, and event variables—shall be limited to the procedural context.

<< Previous | Next >>

Nets, Regs, and logic

Verilog-2001 states that a net can be written by one or more continuous assignments, primitive outputs, or through module ports. The resultant value of multiple drivers is determined by the resolution function of the net type. A net cannot be procedurally assigned. If a net on one side of a port is driven by a variable on the other side, a continuous assignment is implied. A force statement can override the value of a net. When released, it returns to the resolved value.

Verilog-2001 also states that one or more procedural statements can be written to variables, including procedural continuous assignments. The last write determines the value. A variable cannot be continuously assigned. The force statement overrides the procedural assign statement, which in turn overrides the normal assignments. A variable cannot be written through a port; it must go through an implicit continuous assignment to a net.

In SystemVerilog, all variables can now be written either by one continuous assignment or by one or more procedural statements, including procedural continuous assignments. It shall be an error to have multiple continuous assignments or a mixture of procedural and continuous assignments writing to any term in the expansion of a written longest static prefix of a logic variable. All data types can be written through a port.

SystemVerilog variables can be packed or unpacked aggregates of other types. Multiple assignments made to independent elements of a variable are examined individually. An assignment where the left-hand side contains a slice is treated as a single assignment to the entire slice. It shall be an error to have a packed structure or array-type written with a mixture of procedural and continuous assignments. Thus, an unpacked structure or array can have one element assigned procedurally, and another element assigned continuously. And, each element of a packed structure or array can have a single continuous assignment. For example, assume the following structure declaration:

struct {
bit [7:0] A;
bit [7:0] B;
byte C;
} abc;

The following statements are legal assignments to struct abc:

assign abc.C = sel ? 8’hBE : 8’hEF;
not (abc.A[0],abc.B[0]),
(abc.A[1],abc.B[1]),
(abc.A[2],abc.B[2]),
(abc.A[3],abc.B[3]);
always @(posedge clk) abc.B <= abc.B + 1;

The following additional statements are illegal assignments to struct abc:

// Multiple continuous assignments to abc.C
assign abc.C = sel ? 8’hDE : 8’hED;
// Mixing continuous and procedural assignments to abc.A
always @(posedge clk) abc.A[7:4] <= !abc.B[7:4];

For the preceding rule, a declared variable initialization or a procedural continuous assignment is considered a procedural assignment. A force statement is neither a continuous nor a procedural assignment. A release statement shall not change the variable until there is another procedural assignment or shall schedule a re-evaluation of the continuous assignment driving it. A single force or release statement shall not be applied to a whole or part of a variable that is being assigned by a mixture of continuous and procedural assignments.

A continuous assignment is implied when a variable is connected to an input port declaration. This makes assignments to a variable declared as an input port illegal. A continuous assignment is implied when a variable is connected to the output port of an instance. This makes procedural or continuous assignments to a variable connected to the output port of an instance illegal.

SystemVerilog variables cannot be connected to either side of an inout port. SystemVerilog introduces the concept of shared variables across ports with the ref port type.

The compiler can issue a warning if a continuous assignment could drive strengths other than St0, St1, StX, or HiZ to a variable. In any case, SystemVerilog applies automatic type conversion to the assignment, and the strength is lost.

An assignment as part of the logic declaration is a variable initialization, not a continuous assignment. For example:

wire w = vara & varb; // continuous assignment
logic v = consta & constb; // initial procedural assignment
logic vw; // no initial assignment
assign vw = vara & varb; // continuous assignment to a logic
real circ;
assign circ = 2.0 * PI * R; // continuous assignment to a real

<< Previous | Next >>

Array methods

Array Locator Methods

Locator methods iterate over the array elements, which are then used to evaluate the expression specified by the with clause. The iterator argument optionally specifies the name of the variable used by the with expression to designate the element of the array at each iteration. If it is not specified, the name item is used by default. The scope for the iterator name is the with expression.

The following locator methods are supported (the with clause is mandatory) :

  • find(): returns all the elements satisfying the given expression
  • find_index(): returns the indexes of all the elements satisfying the given expression
  • find_first(): returns the first element satisfying the given expression
  • find_first_index(): returns the index of the first element satisfying the given expression
  • find_last(): returns the last element satisfying the given expression
  • find_last_index(): returns the index of the last element satisfying the given expression

For the following locator methods, the with clause (and its expression) can be omitted if the relational operators (<, >, ==) are defined for the element type of the given array. If a with clause is specified, the relational operators (<, >, ==) must be defined for the type of the expression.

  • min(): returns the element with the minimum value or whose expression evaluates to a minimum
  • max(): returns the element with the maximum value or whose expression evaluates to a maximum
  • unique(): returns all elements with unique values or whose expression is unique
  • unique_index(): returns the indexes of all elements with unique values or whose expression is unique

Examples:

string SA[10], qs[$];
int IA[*], qi[$];
// Find all items greater than 5
qi = IA.find( x ) with ( x > 5 );
// Find indexes of all items equal to 3
qi = IA.find_index with ( item == 3 );
// Find the first item equal to Bob
qs = SA.find_first with ( item == "Bob" );
// Find the last item equal to Henry
qs = SA.find_last( y ) with ( y == "Henry" );
// Find the index of the last item greater than Z
qi = SA.find_last_index( s ) with ( s > "Z" );
// Find the smallest item
qi = IA.min;
// Find the string with a largest numerical value
qs = SA.max with ( item.atoi );
// Find all unique strings elements
qs = SA.unique;
// Find all unique strings in lower-case
qs = SA.unique( s ) with ( s.tolower );

Array ordering methods

Array ordering methods can reorder the elements of one-dimensional arrays or queues.
The general prototype for the ordering methods is:

function void ordering_method ( array_type iterator = item )

The following ordering methods are supported:

  • reverse(): reverses all the elements of the array (packed or unpacked). Specifying a with clause shall be a compiler error.
  • sort(): sorts the unpacked array in ascending order, optionally using the expression in the with clause.

The with clause (and its expression) is optional when the relational operators are defined for the array element type.

  • rsort(): sorts the unpacked array in descending order, optionally using the expression in the with clause.

The with clause (and its expression) is optional when the relational operators are defined for the array element type.

  • shuffle(): randomizes the order of the elements in the array. Specifying a with clause shall be a compiler error.

Examples:

string s[] = { "hello", "good", "morning" };
s.reverse; // s becomes { "morning", "good", "hello" };
logic [4:1] a = 4’bXZ01;
a.reverse; // a becomes 4’b10ZX
int q[$] = { 4, 5, 3, 1 };
q.sort; // q becomes { 1, 3, 4, 5 }
struct { byte red, green, blue } c [512];
c.sort with ( item.red ); // sort c using the red field only
c.sort( x ) with ( x.blue << 8 + x.green ); // sort by blue then green

Array reduction methods

Array reduction methods can be applied to any unpacked array to reduce the array to a single value. The expression within the optional with clause can be used to specify the item to use in the reduction.

The prototype for these methods is:

function expression_or_array_type reduction_method (array_type iterator = item)

The method returns a single value of the same type as the array element type or, if specified, the type of the expression in the with clause. The with clause can be omitted if the corresponding arithmetic or boolean reduction operation is defined for the array element type. If a with clause is specified, the corresponding arithmetic or boolean reduction operation must be defined for the type of the expression.

The following reduction methods are supported:

  • sum(): returns the sum of all the array elements, or if a with clause is specified, returns the sum of the values yielded by evaluating the expression for each array element.
  • product(): returns the product of all the array elements, or if a with clause is specified, returns the product of the values yielded by evaluating the expression for each array element.
  • and(): returns the bit-wise AND ( & ) of all the array elements, or if a with clause is specified, returns the bit-wise AND of the values yielded by evaluating the expression for each array element
  • or(): returns the bit-wise OR ( | ) of all the array elements, or if a with clause is specified, returns the bitwise OR of the values yielded by evaluating the expression for each array element
  • xor(): returns the logical XOR ( ^ ) of all the array elements, or if a with clause is specified, returns the XOR of the values yielded by evaluating the expression for each array element.

Examples:

byte b[] = { 1, 2, 3, 4 };
int y;
y = b.sum ; // y becomes 10 => 1 + 2 + 3 + 4
y = b.product ; // y becomes 24 => 1 * 2 * 3 * 4
y = b.xor with ( item + 4 ); // y becomes 12 => 5 ^ 6 ^ 7 ^ 8

Iterator index querying

The expressions used by array manipulation methods sometimes need the actual array indexes at each iteration, not just the array element. The index method of an iterator returns the index value of the specified dimension.

The prototype of the index method is:

function int_or_index_type index ( int dimension = 1 )

The slowest variation is dimension 1. Successively faster varying dimensions have sequentially higher dimension numbers. If the dimension is not specified, the first dimension is used by default. The return type of the index method is an int for all array iterator items except associative arrays, which returns an index of the same type as the associative index type.

For example:

int arr[]
int mem[9:0][9:0], mem2[9:0][9:0];
int q[$];
//Finds all items equal to their position (index)
q = arr.find with ( item == item.index );
//Finds all items in mem that are greater than the corresponding item in mem2
q = mem.find( x ) with ( x > mem2[x.index(1)][x.index(2)] );

<< Previous | Next >>

Puzzles

Que 16: There are 100 water bottles. One of the bottles contains poisoned water. If a rat drinks poisoned water he will die after one hour of it. You have 1 hour to find out which bottle has the poison. How many minimum rats are needed to figure out which bottle contains poison?
Ans 16:
We can use digital logic to find out the poisoned bottle. Also, the rat will die in 1 hour and we have only 1 hour to figure it out we can give that water to rat only once. If we use the digital logic 100 numbers can be represented in 8 bits. If we convert each number into a digital number and give the water to those rats only if that position contains 1. Suppose the poison is in the 10th (00001010)bottle we will give the water to the 2nd and 4th rats. After 1 hour, we check which rats have died(represent logic 1) and which have not died(represent logic 0) and we can form back the number and we can figure it out. So, we need 8 rats to figure out the poisoned water bottle.


Que 17: You have a box with 10 pairs of blue socks, 10 pairs of black socks, and 10 pairs of gray socks of the same size. You can pick one sock at a time. How many times do you have to pick the socks from the box to ensure that you have at least one pair of socks with the same color?
Ans 17:
You have a total of 30 pairs of socks. If you pick 30 socks there might be a chance that all the socks are of the same leg. So, if we pick 1 more sock It will ensure that we will have a pair of socks. So we need to pick 31 socks from the box.


Que 18: You have a rectangular sheet with a circular hole anywhere in the sheet, you know the center of the sheet and the center of the hole, How will you divide the sheet into two parts such that their areas are equal?
Ans 18:
If we draw a straight line from the center of the rectangle in any direction it will divide the rectangle into 2 equal halves and the same in the circle. So we can draw a line that passes through the center of both rectangle and circle. This line will divide the sheet into two parts with equal area.


Que 19: You have a balance scale, You need to measure integer weights from 1kg. to 40kgs. only. How many minimum numbers of weights do you need if you can put weights on one side of the scale?
Ans 19:
We have weights that add up to 40 kg. we have 2 choices either we put it on balance or won’t put it. Hence, we can use binary weights which can count from 1 to 40. So the weights will be 20, 21, 22, 23, 24, 25 which is 1, 2, 4, 8, 16, 32. A total of 6 weights are needed.


Que 20: In the previous question, what is the minimum number of weights needed if you can put your weights on both sides of the scale.
Ans 20:
In this question, we can put the weights on either side of the balance scale or don’t put them on the scale. So, you will have 3 options +1, 0, or -1. We can use base 3 combinations of the weights 30, 31, 32, 33 which is 1, 3, 9, 27. A total of 4 weights are needed.

<< Previous | Next >>