[sv-bc] DataTypes: Background on primary issues

From: Kathy McKinley <mckinley@cadence.com>
Date: Wed Oct 27 2004 - 18:57:14 PDT

Hello,

I have appended a brief write-up that served as the basis for
a slide presentation at the October p1800 meeting. This presentation
covered justification for extending SystemVerilog to allow new
datatypes on nets, as well as an overview of possible issues.
It is my understanding that the slides themselves (which are a
subset of this information) are available as a part of the meeting
minutes.

Kathy

---------------------------------------------------------------------

SystemVerilog extended Verilog by adding powerful new datatypes and
operators that can be used to declare and manipulate parameters and
variables. Extensions like packed structs provide a very convenient
abstraction for manipulating an object that is really just a bit vector.

SystemVerilog did not extend these new datatypes to nets. However,
with the addition of continuous assignments to variables, hardware
designers can use the extended datatypes with variables to model
many common network behaviors. Users would like to have these
convenient abstractions for nets too, because other common network
behaviors -- bidirectionality, multiple driver resolution, and delays
-- cannot be modeled with variables.

The IEEE 1364 working group endorsed the concept of datatype
orthogonality as the way to extend SystemVerilog datatypes to nets.
Orthogonality is a fundamental principle of good language design.
Datatype orthogonality means that the rules for how an object is updated
are independent from the set of values that the object can have.

In most respects, extending SystemVerilog to allow new datatypes on
nets is very straightforward. The LRM might need to talk about datatypes
a little differently, and the net and port declaration syntax needs
extension, but the right thing to do is obvious and such changes
would not impact existing SystemVerilog designs.

However, there appears to be a small number of areas where the "right"
answer is not obvious. Clarifications, restrictions, or perhaps even
minor changes might be required. A special datatypes subgroup of the
behavioral task force was formed to identify and propose resolutions
for such issues.

The datatypes group adopted the classical programming language view
of a datatype as a set of values and corresponding operations.
The following issues were identified as needing exploration and
resolution:

    - What are the semantics of nets and ports declared as two-state?
      How are multiple drivers handled? How are mixed 2-state and 4-state
      connections handled?

    - How do you use new datatypes to declare ports? When is a port
      declaration a variable, and when is it a net?

    - What are the semantics and issues when ports using new datatypes
      are connected to Verilog 2001 style ports?

The following discussion explores the idea of datatype orthogonality
in a little more detail, and then covers major aspects of the three
issues listed above.

-------------------
WHAT IS A DATATYPE?
-------------------

You can look at Verilog data objects as having two different
attributes.

One is the "kind" of the object (i.e., variable vs. parameter
vs. net) and the other is the "datatype" of the object (integer
vs. real vs. scalar bit, etc).

Roughly, the object kind indicates what you can do with the object.
Only parameters can be modified with defparam statements,
only variables can be assigned by procedural assignments,
only nets have values that are resolved from their drivers, etc.

Roughly, the datatype of an object indicates the values the object
can take on. An object of type 'real' can take on the value 3.14,
an object of a bit vector type can take on the value 4'b0xz1, etc.

These two attributes of an object are largely orthogonal. As
examples, a net can be of most any datatype, and a bit vector can
be the datatype of most any kind of object.

--------------
TWO-STATE NETS
--------------

Verilog defines a variety of network resolution behaviors to accurately
model real hardware at different levels of abstraction: RTL, gate level,
and switch level. Built-in algorithms rely on drivers, strength, net type
(wire, trireg, etc.), and primitive properties (cmos, tran, etc.)
to determine the value of a Verilog net at any given time. The user does
not use language mechanisms to invent network behavior; the behavior is
built into the language.

Verilog nets as defined today are inherently four-state, logic-based
entities. The set of four logic values is not some abstraction like
an enumeration -- each of these values has a vital role to play in the
built-in mechanisms that simulate real hardware behavior. X and Z
values are required for these built-in mechanisms to work as expected.
The Z value is critical for accurate net resolution, and the X value
is necessary for correct initialization behavior.

At the time that the transition from 1364 to P1800 began, the datatypes
subgroup was moving rapidly towards a consensus on a proposal for how
to handle two-state nets. Maintaining accurate hardware behavior was
a paramount consideration. The favored approach was very similar to
the way that SystemVerilog treats packed structs with mixed two-state
and four-state members. The next few paragraphs provide an overview
of such an approach.

Network resolution is four-state, and the semantics for computing the
value of a net from its drivers remains unchanged. Declaring a net
as two-state does not change the way that it is resolved; however,
it does change the way that the net is read. If a net or port is
declared to be two-state ("bit", "int", etc.), then when that net is
read in procedural code, its value is converted to two-state with an
implicit type cast.

The procedural contexts (as defined by Verilog 2001 and extended
by SystemVerilog) are the following constructs:

    initial
    always
    always_comb
    always_ff
    always_latch
    final
    program
    task
    function

The value of a net that is declared as two state is *not* converted
in network contexts. Network contexts include continuous assignments
(including implicit continuous assignments at port connections),
specify blocks, and primitives. This means that drivers are not
converted prior to resolution, and so Z values have their intended
effect.

Port collapsing may result in two different net declarations referring
to the same simulated net. Port collapsing is allowed for port connections
where one declaration is two-state and the other is four-state. Due to
four-state network resolution, the network value in this case is computed
correctly, and all network contexts see this four-state value. In procedural
contexts, port collapsing can result in the same simulated net being read
as two-state via one declaration and as four-state via another.

Here is a very simple example that illustrates these concepts:

    module top;
        wire my_net;
        bottom b1 (my_net);
    endmodule

    module bottom ( input wire bit my_port );
        initial $monitor ("my_port = %b, my_net = %b", my_port, top.my_net);
    endmodule

A wire that is declared as four state, my_net, is connected to a port
that is declared as two state, my_port. The simulated net has no drivers,
so its value is Z. The initial statement is a procedural context, so an
implicit type cast is performed for the display of my_port (because it
is declared two-state), but not for the hierarchical reference to my_net:

    my_port = 0, my_net = z

This approach to handling two state in networks offers several advantages:

    1) Accurate hardware behavior is maintained.

    2) The rules are simple.

    3) The approach builds upon the treatment of packed structs and
       unions that contain mixed logic types, providing consistency
       for users.

    4) Mixed two-state/four-state network simulation matches synthesis
       results in "copies", e.g.

       wire logic a,c;
       wire bit b;
       assign a=b;
       assign b=c;

    5) The implementation choice of implicit continuous assignments at
       port connections vs. port collapsing (for performance and capacity)
       does not produce any new visible differences.

------------------
DATATYPES ON PORTS
------------------

If you are going to declare a net with a new datatype, you will want
to be able to use that datatype for connections to that net throughout
the design. What does a port declaration for a net with a new datatype
look like? It might be helpful to consider output, inout, and input ports
separately.

Output ports
------------

SystemVerilog extends Verilog output port declarations to allow
variables declared with the new datatypes, like this:

    output bus_type p;

An obvious way to make that output port a net rather than a variable
would be to require a net type in front of the datatype name, like this:

    output wire bus_type p;

Inout ports
-----------

SystemVerilog does not allow an inout port declaration to use a new
datatype, because it assumes that such a declaration would be a variable,
and variables cannot model bidirectional behavior.

There are two obvious possibilities for declaring an inout port
that is a net. One form would allow an explicit net type:

    inout wire bus_type p;

A second form would not include a net type, and would assume the default
net type for the port:

    inout bus_type p;

Verilog traditionally tries to do what the user wants, without unnecessary
baggage. It would be fitting to assume that any inout port is a net,
and to allow both forms of declaration shown above.

Input ports
-----------

SystemVerilog allows you to connect a variable to an input port declaration:

    input bus_type p;

This connection implies a continuous assignment, thus making any other
assignments to the variable illegal, including an implied continuous
assignment from a connection to a lower-level output or inout port.

An obvious extension to SystemVerilog for datatypes on nets would be
to allow you to declare an input port with a net type:

    input wire bus_type p;

The intent implied by the variable continuous assignment rules raises
an interesting question for input ports, because the intent is not
fulfilled if this variable is connected to a lower-level port that
is a net, for example:

    input p;

In Verilog 2001, an input port is always a net, and it is perfectly legal
for an input port to have drivers. In fact, an implementation must coerce
the port to inout or warn you if it does not (drivers are not silently
ignored). This sort of connection bypasses the strictly input semantic
that appears to be intended for the port. Inaccurate port direction
in existing Verilog designs and Verilog netlisting tools is rampant.

The SystemVerilog input port variable is very close to being a net,
particularly with the net-style force/release semantics that apply
to a variable with a continuous assignment. A powerful extension might
promote this input port to a net, and define more comprehensive rules
to enforce the intended restrictions on drivers.

An input port that is a net offers the following advantages:

    1) You can apply timing (SDF) to the port.

    2) Tool providers can implement port collapsing to get performance
       and capacity improvements for a deep hierarchy of connections.

    3) Behavior between new SystemVerilog ports and Verilog 2001 ports
       is closer to what the user expects.

    4) Input ports that are nets are suitable for connection to other
       language domains, like VHDL.

Given that reference ports are available to pass variables through
the design hierarchy, how do the benefits of this second form of
variable connection compare to the benefits of an input port that
is a net?

The "net or variable" rule for a port could be very simple. Input and
inout ports are nets, and the net type in the declaration is optional.
An output port that is declared with a datatype name is a variable,
unless the declaration includes an explicit net type.

The datatypes group had not yet considered all of these possibilities
for variable/net ports when the transition to p1800 began. This discussion
is intended to provide a feel for both the options and the scope of
consideration that might be required to extend the new datatypes to ports
that are nets.

--------------------------------
CONNECTION TO VERILOG 2001 PORTS
--------------------------------

SystemVerilog allows variables to be driven by a single continuous
assignment, like nets. This includes connecting variables to the "sink"
side of a port (an input port in a module declaration, or an output port
of a module instantiation). Unlike nets, they are not allowed to have
multiple drivers, because their behavior would not resemble real hardware
if they did.

Some design styles restrict the use of multiple-driver nets. It has been
suggested that if variables are used for connections, their limitations
will have the side effect of acting as a design rule check. This is only
true if a hardware net is represented with a variable everywhere in the
hierarchy. If some part of the hierarchy (perhaps legacy code or some
third-party IP) uses a net, then multiple drivers connected to that portion
of the net will not be caught.

For example,

    // New design in SystemVerilog
    module top;
      logic mout;
      ...
      mux m1(sel, in0, in1, mout);
    endmodule

    // Legacy Verilog code
    module mux (sel, in0, in1, mout);
      input sel, in0, in1;
      output mout;
      
      bufif0 b0(mout, sel, in0);
      bufif1 b1(mout, sel, in1);
    endmodule

Inside module mux, mout has two drivers. This is legal because it is
implicitly a wire. However, the logic variable mout in module top only
has one driver: the implicit continuous assignment from the output port
of m1. This is legal also. In the actual hardware, the wire and the
variable will become the same net, which has two drivers. The limitation
on variables has not enforced the design rule. This is not surprising,
since it was not designed for that purpose.

A new net type for enforcing single driver semantics for a net was
proposed to the IEEE 1364 working group. The new net type, wone,
explicitly indicates a desire for a net with only one driver.
For example, the top-level module can be rewritten as:

    // New design in NC-Verilog
    module top;
      wone logic mout;
      ...
      mux m1(sel, in0, in1, mout);
    endmodule

Because of port collapsing, the mout nets inside and outside module m1
will be collapsed into a single wone net. The presence of multiple
drivers on that net will be detected and produce an error.

A wone net type could complement the variable continuous assignment
rules by providing single driver checking for nets.
Received on Wed Oct 27 18:57:26 2004

This archive was generated by hypermail 2.1.8 : Wed Oct 27 2004 - 18:57:28 PDT