Change to use static by default, reference class members, provide example of automatic usage.
Resolve Editor’s Note: No syntax or examples of these new attributes was
provided by the SV-EC.
Change as shown in red:
In Verilog-2001, the
default lifetime for tasks and functions is static. Automatic tasks and functions must be explicitly
declared, using the automatic keyword.
SystemVerilog adds an
optional qualifier to specify the default
lifetime of all tasks and functions declared within a
module, interface, or program (see Section 15).
The lifetime qualifier is
automatic or static. The default lifetime is
static for modules, and automatic for the program block (see section 15).
program
automatic test ;
task foo( int a ); ... endtask // arguments and variables in foo are automatic
endmodule
Class methods are by
default automatic, regardless of the lifetime attribute of the scope
in which they are declared. Classes are discussed in section 11.
Editors Note: This qualifier alters
the BNF rules as follows:
module_declaration ::= { attribute_instance } module_keyword [ lifetime ] module_identifier
[ parameter_port_list ] list_of_ports ; [ timeunits_declaration
] { module_item } endmodule | { attribute_instance } module_keyword [ lifetime ] module_identifier
[ parameter_port_list ] [
list_of_port_declarations ] ;
[ timeunits_declaration ] { non_port_module_item } endmodule task_declaration ::= task [ lifetime ] [ interface_identifier
. ] task_identifier
; { task_item_declaration } { statement } endtask [ : task_identifier ] | task [ lifetime ] [
interface_identifier . ] task_identifier ( task_port_list
) ; { block_item_declaration } { statement } endtask [ : task_identifier ] function_declaration ::= function [ lifetime ] [ signing ] [ range_or_type ] [ interface_identifier . ]
function_identifier ; { function_item_declaration } { function_statement } endfunction [ : function_identifier ] | function [ lifetime ] [
signing ] [ range_or_type ] [ interface_identifier . ]
function_identifier ( function_port_list ) ; { block_item_declaration } { function_statement } endfunction [ : function_identifier ] lifetime ::= static
| automatic // This production already exists
Add const (plus example), include comment on simulation semantic for var updates, add restriction on wire usage.
Change as shown in red:
When the argument is passed
by reference, both the caller and the subroutine share the same representation
of the argument, so any changes made to the argument either within the caller
or the subroutine will be visible to each other. The semantics of assignments to variables passed by
reference is that changes are seen outside the subroutine immediately (before
the subroutine returns). Only variables, not wires, can be passed by reference.
Add the following paragraph at the end of the section.
To protect arguments passed
by reference from being modified by a subroutine, the const qualifier can be used
together with ref to indicate that the argument, although
passed by reference, is a read-only variable.
task show( const ref
char [] data );
for( int j = 0; j < data.size
; j++ )
$display( data[j]
); // data can be read but not
written
endtask
When the formal
argument is declared as a const ref,
the subroutine cannot alter the variable, and an attempt to do so will generate
compiler error.
Add clarification about mixed named and default argument usage.
Add paragraph at end of section as shown in red:
If the arguments have
default values, they are treated like parameters to module instances. If the arguments
do not have a default, then they must be given or the compiler shall issue an
error.
If both positional and named arguments are
specified in a single subroutine call then all the positional arguments must
come before the named arguments. Then, using the same example
as above:
fun( .s("yes"),
2 ); // illegal
fun( 2, .s("yes") ); // OK
Write a proposal to have c++ like namescope to access members.
With the addition of the :: operator enables reference to both static data members and static members. With this new feature (defined in 11.20) it is now useful to include static methods (11.8.1).
Add the following section after Section 11.8 as shown in red:
11.8.1 Static methods
Methods can be declared as
static. A static method is subject to all the class scoping and access rules,
but behaves like a regular subroutine that can be called outside the class,
even with no class instantiation. A static method has no access to non-static
members (properties or methods), but it may directly access static class
properties or call static methods of the same class. Access to non-static
members or to the special this handle within the body of a
static method is illegal and results in a compiler error. Static methods cannot
be virtual.
class id;
static int current = 0;
static
function int next_id();
next_id = ++current; // OK to access static class property
endfunction
endclass
A static method is different from
a method with static lifetime. The former refers to the lifetime of the method
within the class, while the latter refers to the lifetime of the arguments and
variables within the task.
class TwoTasks;
static task foo(); ... endtask // static class method with automatic variable lifetime
task static
bar(); ... endtask // non-static class method with static variable lifetime
endclass
Add the following section between Section 11.19 and Section
11.20 (with this being the new Section 11.20) as shown in red:
11. 20 Class scope resolution operator ::
The class scope operator :: is used
to specify an identifier defined within the scope of a class, and it has the
following form:
scoped_expression ::= class_name
:: {class_name :: }
identifier
Identifiers on the left side of
the scope-resolution operator (::) can be only class names.
Because classes and other scopes
can have the same identifiers, the scope resolution operator uniquely
identifies a member of a particular class. In addition to disambiguating class
scope identifiers, the :: operator also allows access to static members (properties and
methods) from outside the class, as well as access to public or protected
elements of a super-classes from within the derived classes.
class Base;
typedef enum {bin,oct,dec,hex} radix;
static task print( radix r, integer
n ); ... endtask
endclass
...
Base b = new;
int bin = 123;
b->print( Base::bin, bin ); // Base::bin and
bin are different
Base::print( Base::hex, 66 );
In SystemVerilog the class scope
operator applies to all static elements of a class: static class properties,
static methods, typedefs, enumerations, struct, union, and nested class declarations. Class-scope
resolved expressions can be read (in expressions), written (in assignments or
subroutines calls) or triggered off (in event expressions). They can also be
used as the name of a type or a method call.
Like modules, classes are scopes
and can nest. Nesting allows hiding of local names and local allocation of
resources. This is often desirable when a new type is needed as part of the
implementation of a class. Declaring types within a class helps prevent name
collisions, and cluttering the outer scope with symbols that are used only by
that class. Type declarations nested inside a class scope are public and can be
accessed outside the class.
class StringList;
class Node; // Nested class for a node in a linked list.
string name;
Node link;
endclass
endclass
class StringTree;
class Node; // Nested class for a node in a binary tree.
string name;
Node left, right;
endclass
endclass
// StringList::Node
is different from StringTree::Node
The scope resolution operator
enables:
_ Access to static public members (methods and properties) from outside
the class hierarchy.
_ Access to public or protected class members of a super-class from
within the derived classes.
_ Access
to type declarations and enumeration labels declared inside the class from
outside the class hierarchy or from within derived classes.
Clarify order that semaphores and mailboxes do something
Change as shown in red:
The semaphore waiting queue
is First-In First-Out (FIFO). This
does not guarantee the order in which processes will arrive at the queue, only
that their arrival order will be preserved by the semaphore.
Change as shown in red:
The mailbox waiting queue
is FIFO. This does not guarantee
the order in which processes will arrive at the queue, only that their arrival
order will be preserved by the mailbox.
Resolve Editor’s
Note: Has the changed keyword been removed from SystemVerilog?
Change as shown in red:
clocking
dram @(changed
clk);
input
#1ps address;
input
#5 output #6 data;
endclocking
Editor’s Note: Has the changed keyword
been removed from SystemVerilog?
Resolve Editor’s Note: Has the changed keyword been removed from
SystemVerilog?
Change as shown in red:
clocking
mem @(changed clock);
input
instruction = { opcode, regA,
regB[3:1] };
endclocking
Editor’s Note: Has the
changed keyword been removed from SystemVerilog?
Resolve Editor’s
Note: The addition in the preceding paragraph from EC-CH81 of a step being the
“smallest global precision” is ambiguous. What if no global timeprecision
was specified? Is the module’s precision used? Is the timescale precision used?
What’s the precedence? I suspect what was intended is that “a step is an
increment of 1 simulator time unit. The simulator time unit is defined in the
Verilog 1364 standard”. [1364-2001 section 19.8 defines the simulator time
as “The smallest time_precision argument of all the
`timescale compiler directives in the design determines the precision of the
time unit of the simulation.“. The PLI sections also
refer to “simulator time unit” in several places, and refer to 19.8 for the
definition of the simulator time unit”.
Note:
The definition in the 1364 standard does not define a useable term, it describes what determines the “precision of the
time unit of simulation”, but is incomplete since it does not account for the timeprecision and timeunit statements of SystemVerilog.
Change as shown in red:
time_literal
::= // from Annex A.8.4
unsigned_number time_unit
| fixed_point_number
time_unit
time_unit ::= s | ms |
us | ns | ps | fs | step
Change as shown in red:
Time is written in integer
or fixed point format, followed without a space by a time unit (fs
ps ns us ms s step).
Change as shown in red:
Unless otherwise specified,
the default input skew is 1step and the default output skew is 0. A step is a special time unit whose
value is defined in Section 17.6. Like all
other time units, step is not a keyword. A 1step input skew allows input signals to sample their
steady-state values immediately before the clock event (i.e., at
read-only-synchronize immediately before time advanced to the clock event).
Unlike other time units, which represent physical units, a step cannot be used
to set or modify the either the precision or the timeunit.
Editor’s Note: The addition in the
preceding paragraph from EC-CH81 of a step being the “smallest global
precision” is ambiguous. What if no global timeprecision
was specified? Is the module’s precision used? Is the
‘timescale precision used? What’s the precedence.
I suspect what was intended is that “a step is an increment of 1 simulator
time unit. The simulator time unit is defined in the Verilog 1364 standard”. [1364-2001
section 19.8 defines the simulator time as “The smallest time_precision
argument of all the `timescale compiler directives in the design determines the
precision of the time unit of the simulation.“. The
PLI sections also refer to “simulator time unit” in several places, and refer
to 19.8 for the definition of the simulator time unit”.
Add the following as a new paragraph at the end of the section as shown in red:
The timeunit
and timeprecision
keywords shall precede any other item
in the top level, module, or interface, because the other items can contain
delays and therefore can be dependent on the time unit.
The global time precision is the minimum of all the timeprecision statements and the smallest time precision
argument of all the `timescale
compiler directives (known as the precision of the time unit of the simulation
in Section 19.8 of the IEEE 1364-2001 standard) in the design. The step time unit is equal to the global
time precision.
Change as shown in red:
time_unit ::= s | ms |
us | ns | ps | fs | step
For syntax of disabling constraints and random variables constraint methods, or system task take a look at this in more detail.
Change as shown in red:
20.15
Disabling random variables
The rand_mode() method
can be used to control whether a random variable is active or inactive. When a
random variable is inactive, it is treated the same as if it had not been
declared rand or randc. Inactive variables are not
randomized by the randomize() method, and their values are treated
as state variables by the solver. All
random variables are initially active.
20.15.1 rand_mode()
The syntax for the rand_mode() method
is:
task object[.random_variable]::rand_mode( bit on_off );
or
function int object.random_variable::rand_mode();
object is any expression that yields
the object handle in which the random variable is defined.
random_variable is the name of the random
variable to which the operation is applied.
If it is not specified (only allowed when called
as a task), the action is applied to all random variables within the
specified object.
When called as a
task, the argument to the rand_mode method determines the operation to be performed:
Table 20-1:
rand_mode first argument
Value |
Meaning |
Description |
0 |
OFF |
Sets the specified variables
to inactive so that they are not randomized on subsequent calls to the randomize() method. |
1 |
ON |
Sets the specified variables
to active so that they are randomized on subsequent calls to the randomize() method. |
For
array variables, random_variable
can specify individual elements using the corresponding index. Omitting the index results in all the elements of the array being affected
by the call.
If the
random_variable is an object handle, only the mode
of the variable is changed, not the mode of random variables within that object
(see Global Constraints in Section 20.11).
A compiler
error is issued if the specified variable does not exist within the class
hierarchy or it exists but is not declared as rand or randc.
When called as a function, rand_mode() returns the current active state of the specified
random variable. It returns 1 if the variable is active (ON),
and 0 if the variable is inactive (OFF).
The
function form of rand_mode() only
accepts singular variables, thus, if the specified variable is an array, a
single element must be selected via its index.
Example:
class Packet;
rand
integer source_value, dest_value;
... other declarations
endclass
int ret;
Packet packet_a = new;
// Turn off all
variables in object.
packet_a.rand_mode(0);
// ... other code
// Enable source_value.
packet_a.source_value.rand_mode(1);
ret = packet_a.dest_value.rand_mode();
This
example first disables all random variables in the object packet_a, and then enables only
the source_value variable. Finally, it sets the ret variable to the active status of variable dest_value.
The rand_mode() method is
built-in and cannot be overridden.
Change as shown in red:
20.16
Disabling constraints
The constaint_mode() method
can be used to control whether a constraint is active or inactive. When a constraint is inactive, it is not considered
by the randomize() method. All constraints are initially active.
20.16.1
constraint_mode()
The
syntax for the constraint_mode() method is:
task object[.constraint_name]::constraint_mode( bit on_off );
or
function int object.constraint_name::constraint_mode();
object is any expression that yields
the object handle in which the constraint is defined.
constraint_name is the name of the constraint
block to which the operation is applied. The constraint name can be the name of
any constraint block in the class hierarchy.
If no constraint name is specified (only allowed
when called as a task), the operation is applied to all constraints
within the specified object.
When called as a
task, the argument to the constraint_mode method determines the operation to be performed:
Table 20-2:
constraint_mode first argument
Value |
Meaning |
Description |
0 |
OFF |
Sets the specified
constraint block to active so that it is considered by subsequent calls to the randomize() method. |
1 |
ON |
Sets the specified
constraint block to inactive so that it is not enforced on
subsequent calls to the randomize()
method. |
A compiler error is issued if
the specified constraint block does not exist within the class hierarchy.
When called as a function, constraint_mode() returns the current active state of the specified
constraint block. It returns 1 if the
constraint is active (ON), and 0 if the constraint is
inactive (OFF).
Example:
class Packet;
rand
integer source_value;
constraint filter1 { source_value > 2 * m; }
endclass
function
integer toggle_rand( Packet p );
if( p.filter1.constraint_mode() )
p.filter1.constraint_mode(0);
else
p.filter1.constraint_mode(1);
toggle_rand = p.randomize();
endfunction
In
this example, the toggle_rand function first checks
the current active state of the constraint filter1 in the specified Packet
object p. If the constraint is active
then the function will deactivate it; if
it’s inactive the function will activate it.
Finally, the function calls the randomize method to generate a new
random value for variable source_value.
The constraint_mode() method is
built-in and cannot be overridden.