Subject: RE: Issues List - Additional Details
From: David Smith (David.Smith@synopsys.com)
Date: Tue Jun 11 2002 - 08:38:34 PDT
Stu,
Can you please merge this list and information into the list you were keeping? I believe we have already determined which of these were enhancements, C/C++, or clean-up.
Regards
David
David W. Smith
Mixed-Signal and System Architect
Synopsys, Inc.
9205 SW Gemini Drive
Beaverton, OR 97008
Voice: 503.520.2715
FAX: 503.643.3361
Email: david.smith@synopsys.com
http://www.synopsys.com
-----Original Message-----
From: Erich Marschner [mailto:erichm@cadence.com]
Sent: Monday, June 10, 2002 5:53 PM
To: vlog-pp@eda.org
Subject: Issues List - Additional Details
In the System Verilog meeting last Wednesday, the issues list that I submitted was reviewed, and the items were categorized. Following is the same set of issues, with the categories that I understood were assigned to each, and with the additional detail we promised to provide.
Most items were identified as basic issues (i.e., for cleanup). I've labeled these [Basic].
Some items were specifically noted as documentation issues. I've labeled these [Basic/Doc], or in one specific case, [Basic/BNF].
Some items having to do with interfaces seemed to be both basic and to relate to system level design. I've labeled these as [Basic, System].
Any questions about the detailed comments should be addressed to the person listed as the source of each issue.
Regards,
Erich
-------------------------------------------
Erich Marschner, Cadence Design Systems
Senior Architect, Advanced Verification
Phone: +1 410 750 6995 Email: erichm@cadence.com
Vmail: +1 410 872 4369 Email: erichm@comcast.net
======================================================================
Additional detail for the issues discussed in the System Verilog 3.1 Kickoff Meeting
======================================================================
Section 2 - Issues with Literals (Steve/Cadence) [Basic]
- width/signedness of an unsized literal without a base specifier?
- legal constructs within an array or structure literal?
- legal use of array or structure literals?
a. Is the width of an unsized literal without a base specifier (section 2.3) one bit? This seems to be implied by the wording, but since other unsized constants must be at least 32 bits, it should be made clearer. This is especially important in self-determined contexts. For example, how many bits are printed by $display("%b",'0)?'
b. Are unsized literals without a base specifier considered to be unsigned? The Verilog standard states that based constants are unsigned, while simple decimal numbers without the size and base are signed. This case doesn't really match either. It comes closest to matching the signed case, but the intent was probably for them to be unsigned.
c. What is legal inside an array or structure literal (sections 2.7 and 2.8)? Can strings be used inside them? How precisely must the types match? One of the examples shows a real literal inside a structure literal being assigned to a shortreal element of a structure, which implies some implicit type conversion. And section 7.9 shows examples where the bit widths don't match, again implying conversions. And yet section 7.9 states that each element must match the type being initialized. Since the examples don't actually match exactly, it is not clear what degree of matching is required.
d. Where exactly are array and structure literals legal? They are apparently only supposed to be legal on initializers. However, the example in section 2.8 assigns a structure literal to the struct c in an assignment separate from the declaration of c. Is this just a typo?
e. Since data types can be passed into modules or interfaces, it may not be possible to distinguish an array/structure literal from an ordinary concatenation until elaboration time. This probably doesn't place too much of a burden on the implementation. It does either delay error checking until elaboration, or require duplication of error checking so that errors can be produced as early as possible.
======================================================================
Section 3 - Issues with new data types and keywords (Steve/Cadence) [Basic]
- actual utility of char, shortint, longint, byte, shortreal
- non-orthogonality of definitions
- inconsistent with C definitions
- void type - is it necessary?
The new data types add a lot of new reserved words. From the viewpoint of backward compatibility with Verilog, each of these should be carefully examined for utility to offset the incompatibility introduced.
a. What exactly is the purpose of char? There is no interface to C defined, so it can't be intended for values produced and consumed only by C. And Verilog specifically only handles 8-bit ASCII values, so it can't manipulate char values properly itself when they could be 16-bit Unicode. Trying to use them with Verilog string literals, string I/O, or in combination with ASCII string variables wouldn't work. If it isn't usable, it should be removed.
b. The shortint type has limited utility. There is no interface to C defined, so it can't be needed to match struct layout at an interface. The 16-bit short is rarely used in C, and can usually be replaced with a 32-bit int without any problems. And in the unlikely event that a 16-bit int is really needed, it can always be declared as a packed array of bit. The utility of shortint does not appear to justify the addition of a reserved word.
c. The int type seems reasonable as a general purpose 2-state variable, similar to the Verilog integer. However, one would expect orthogonality between the 2-state and 4-state types. The int type is exactly 32 bits, while the integer type is 32 bits or more. The types really should be orthogonal, rather than an ad hoc collection.
d. The longint type probably has more utility than shortint, since it can't always be replaced with an int. However, it doesn't correspond to a commonly used C type except with a C compiler that is compiling for 64-bit. The need for a 64-bit integer type in Verilog is limited, and can be declared as a packed array of bit if necessary. It doesn't appear to justify the addition of a reserved word.
e. The byte type could be justified by a desire to conveniently declare 2-state strings. However, it does not appear that they can be used for this. String literals can be assigned to arrays of char, but not to arrays of byte. Nor can arrays of byte be used with string I/O or manipulated with Verilog operators or in combination with other strings, which are packed vectors. This actually makes the byte type less useful than an array of bits. And since "byte" is more likely to be used as an identifier name in existing designs than most of the other new types, it creates a more serious backward compatibility issue. The limited utility does not appear to justify the addition of a reserved word that is likely to match existing identifiers.
f. The bit type is needed to support 2-state vectors, though it carries some risk of matching identifiers in existing designs.
g. The logic type has issues that will be discussed elsewhere. The name also carries some risk of matching existing identifiers.
h. The fact that the unsigned keyword is officially reserved does not really avoid backward compatibility issues. I don't know of any implementations that actually reserve it, so it may appear as an identifier in existing Verilog designs. This seems unlikely, and it does add significant utility.
i. The shortreal type adds limited utility. Again, without a direct interface to C, there is no need to match an exact data type. The real data type can be used instead. The use of reals in Verilog is rare enough that the difference in storage space and speed is unlikely to be significant. Also note that most floating point operations in C are automatically done in double precision regardless of the variable types. This means that an operation done with floats in C could get a different answer than an equivalent operation done with shortreal in SystemVerilog, due to different roundoff errors. So if the goal is to match C floating point, then it fails.
j. The void type is unnecessary. It was added to C because C only has functions, and void allows declaring a subroutine without a return value. Verilog already has tasks, so it doesn't need void. There is nothing that can be done with a void function that cannot already be done with a task. There is no need to copy this type from C.
======================================================================
Section 3 - Data packing issue (Kevin/NSC) [Basic]
- it is impossible to implement "union" from the current LRM description
- there are many ways to do it which are not compatible
- encoding of logic types is a factor, and "big-endian" vs. "little-endian"
- unions should have either all logic or all bit as the base type of all elements
- if packing is defined then 'packed' union syntax is redundant
- may be desirable to state the packing/alignment explicitly for software compatibility
[See email on the reflector archive for details from Kevin.]
======================================================================
Section 3 - Type use before definition (Steve, Paul/Cadence) [Basic]
- forces type checking to be post-elaboration
- cause unnecessary complication of analysis, particularly separate analysis
- useful only with pointer types
[This has been discussed before - no additional detail is involved.]
======================================================================
Section 3.1 - Parameterized data types (Stuart/Cadence) [Basic]
- nice, but difficult to use because they cannot be resolved until elaboration
- (can we improve this to better support separate compilation?)
It's nice to be able to use parameters to specify data types (similar to C++ class templates), but in Verilog parameters cannot be resolved until elaboration. The end result is that for such parameterized modules almost no error-checking or code generation can be done until after elaboration. This is painful for the user (due to very late error checking) and complicates tool implementation.
======================================================================
Section 3.4.1 - Issues with Time data type (Steve/Cadence) [Basic]
- need to detail the rules for mixed expressions, scaling, etc.
The specification of the time data type (section 3.4.1) is extremely unclear. The examples are not particularly helpful, since they only involve simple time literals used as delays. There is no specification of what happens when a time literal is assigned to a time variable, or an integer or real value is assigned to a time variable, or a time value is assigned to an integer or real variable, or time and integer values are combined in an expression. It is so unclear that it is hard to even formulate a general question, so I will ask about examples. The answers will help clarify things, but what is really needed is a specification of the underlying rules that produce those answers.
a. If I have the following code:
`timescale 1ns/10ps
time t;
initial
begin
t = 1;
#(t) $display(t);
end
What is the numerical value in the variable t? In normal Verilog, a time variable is just a 64-bit vector, so it would be 1. But the specification seems to indicate that a time variable is this new time data type, so it needs to be scaled. I would guess that this means multiplication by the ratio between the time unit and the time precision, or 100. Does this mean that t gets the scaled value of 100? What if some other module has a precision of 1ps, so that the overall time step for the simulation is 1ps? Does t still get 100 based on the local precision, or 1000 based on the smallest precision? What is the delay produced by the #(t)?
b. If I have the following code:
`timescale 1ns/10ps
time t;
initial
begin
t = 1ns;
#(t) $display(t);
end
what is the numerical value in the variable t? Presumably it is 100, since that is the multiple of the time step. Again, does this depend on the local precision or the overall precision? What is the delay produced by the #(t)? One would hope it is 1ns.
c. If I have the following code:
`timescale 1ns/10ps
integer i;
initial
begin
i = 1ns;
#(i) $display(i);
end
Is this legal? If so, what is the numerical value of the integer variable i? Does this produce a delay of 1ns?
d. If I have the following code:
`timescale 1ns/10ps
time t;
initial
begin
t = 1ns + 10ps;
#(t) $display(t);
#(1ns + 10ps) $display($time);
end
What is the value of t? Presumably both time literals get scaled and then added, so the result is 101.
e. If I have the following code:
`timescale 1ns/10ps
time t;
initial
begin
t = 1ns + 1;
#(t) $display(t);
#(1ns + 1) $display($time);
end
How are mixed expressions like this handled? Note that an integer expression would fully evaluate as an integer and then be scaled for the delay. But a time literal needs to be scaled to the time unit first, and can't be re-scaled again later. How and when are these scalings done?
f. If I have the following code:
`timescale 1ns/10ps
time t1,t2;
initial
begin
t1 = 0.1 + 0.1;
#(t) $display(t);
end
What is the value of t? Presumably it is 20, and the #(t) delays by 200ps. But are those answers obtained by adding and then scaling, or scaling and then adding? Some further questions will expose differences between those.
g. If I have the following code:
`timescale 1ns/10ps
time t;
initial
begin
t = 0.004 + 0.004;
#(t) $display(t);
end
What is the value of t? Are the two reals scaled and truncated to 0, and then added to get 0? Or are they added, then scaled and truncated, producing 1?
h. One possible rule is that operands are all scaled and then combined. But this doesn't work for all types of operands. For example:
`timescale 1ns/10ps
time t;
initial
begin
t = 1ns << 1;
#(t) $display(t);
end
Clearly scaling the 1 by 100 before the shift is undesirable. Perhaps it only scales operands that are not self-determined. And what happens if we try to shift by 1ns? Is this legal? There are no specifications of where times are legal.
i. Even scaling only operands that are not self-determined doesn't always work properly. Whenever dimensional analysis would result in units that are not times, this scaling falls apart. For example:
`timescale 1ns/10ps
time t;
initial
begin
t = 1ns + 1 * 1;
#(t) $display(t);
end
What is the value of t here? If both integer literals get scaled, then the scaling factor gets multiplied in twice. So apparently scaling needs to wait until the integer sub-expression is actually combined with a time (unlike the other integer type conversions in Verilog, which are applied to operands before any operations). But this is not specified anywhere.
======================================================================
Section 3.6 - Implications of Enum type I/O (Steve/Cadence) [Basic]
- need to detail what is expected of Verilog I/O routines to support this
- [also vcd enhancements]
In section 3.6, it is stated that enumerated types can be displayed using the enumerated names. Is this supposed to imply some capability of the Verilog I/O routines? If so, these capabilities need to be defined. If it is just a speculation about what the user interface to some tool might allow during debugging, then this should be made plain.
======================================================================
Section 3.7 - Definition of "masked" and "unmasked" (Steve/Cadence) [Basic/Doc]
- apparently not defined?
Section 3.7 refers to structure members as being masked or unmasked. These terms do not appear to be defined anywhere, and appear to refer to 4-state and 2-state values. The terminology should be fixed.
======================================================================
Section 3.7 - Size requirement(?) on members of a packed union (Steve/Cadence) [Basic/Doc]
- should say "must be the same size", not "are the same size" (?)
The text in section 3.7 stating that members of a packed union "are" the same size should be changed to state that they "must be" the same size, if that is the intent.
======================================================================
Section 3.7 - Passing large structs/arrays (Stuart/Cadence) [Basic, System]
- can this be done by reference instead of value (which would be inefficient)?
Is there a way to pass large structs or arrays to functions/tasks by pointer or as const references, rather than by value? If not, this can be extremely inefficient for large structs or arrays.
======================================================================
Section 3.8 - Conversion of shortreals to 32 bits (Steve/Cadence) [Basic/Doc]
- "bit pattern is preserved" is inconsistent with other conversions
- should use $realtobits if the intent is to transfer the bit pattern
In section 3.8, it is stated that when a shortreal is converted to 32 bits, the bit pattern is preserved (instead of rounding). This is not consistent with the rest of Verilog. If a shortreal converts to int by rounding, then it should convert to 32 bits by rounding. The int type is equivalent to 32 bits. Also, a real converts to a reg by rounding, so a shortreal should do the same. Nothing is said about real transferring its bit pattern when converted to bits, just shortreal. Since the statement is made in the section on casting, it implies that this happens only when casting, and that a conversion on assigning to a variable of that type would behave differently. This statement in the document is a bizarre exception to all related situations. If a real needs its bit pattern transferred to a vector, Verilog provides $realtobits for this purpose. A similar function could be provided for shortreal. Alternately, a union of a shortreal and a bit vector, or a struct or !
! union containing just a shortreal, could be used for conversion.
======================================================================
Section 4.2 - Packed array of signed (Erich/Cadence) [Basic]
- conflict between signed elements and signed whole array
This has been partially addressed in draft 9, but there is still an issue.
Draft 9 says
"If a packed array is declared as signed, then the
array viewed as a single vector shall be signed.
A part-select of a packed array shall be unsigned."
But if a part-select of a signed packed array includes the MSB, shouldn't that part-select be signed? In particular, if the part-select selects all the bits of a signed packed array, shouldn't it be considered signed, since the array as a whole is considered signed?
======================================================================
Section 5.3 Constant expression (Paul/Cadence) [Basic]
- need to define precisely what can/cannot appear in a constant expression
[This has been discussed before - no additional detail is involved.]
======================================================================
Section 6.1 Attribute syntax (Paul/Cadence) [Basic/BNF]
- should factor syntax to improve readability
[This has been discussed before - no additional detail is involved.]
======================================================================
Section 9 - Process execution efficiency when calling C (Kevin/NSC) [C/C++ Intf]
- LRM doesn't say much about calling C from Verilog processes
- should require that C functions can't suspend
======================================================================
Section 9.1 - Interleaving of exection (Stuart/Cadence) [Basic]
- allowing arbitrary interruption is error-prone
- should only allow interruption at synchronization points
Why allow a thread of execution to be interrupted by another thread between any statements? Why not only at synchronization points such as wait (#) or blocking assignments? The current proposal results in a modeling style that is very error prone and provides no benefit in terms of performance or functionality over only allowing interruption at synchronization points.
======================================================================
Section 9.1-Related - Verilog 2001 - Scheduling Algorithm (Shalom/Motorola) [Basic]
- allows interleaving of processes that need to be atomic
- conflicts with requirement that non-blocking assignments execute in order of appearance
- potential problem with scheduling of PLI calls
======================================================================
Section 9.1 - Issues with dynamic processes (Stuart/Cadence) [Basic]
- need the ability to suspend/resume/abort child processes
- need process handles to support this
Ability to use dynamic processes seems incomplete without ability to specify suspend/resume of child processes, and ability to abort child processes. These are needed to model pipelines with stalls, operating systems, etc. The current proposal doesn't seem to have a clean way to return process handles that will be needed once suspend/resume/abort etc are supported in future.
======================================================================
Section 13 - Interfaces vs. Modules (Stuart/Cadence) [Basic, System]
- interfaces and modules are almost the same
- should make them so and simplify definition
I see no reason why "interfaces" and "modules" aren't exactly the same thing. Both can have ports, both can export tasks, both can be parameterized, both represent hierarchical structures, both can have "always" blocks and processes, etc. Making "interfaces" and "modules" be exactly equivalent would go a long way towards simplifying SystemVerilog.
======================================================================
Section 13.1 - Interfaces restrictions (Stuart/Cadence) [Basic, System]
- should allow an interface to contain other modules
- would allow wrapping of a module with an interface
Why can't an interface contain other modules? This would allow existing module implementations to be "wrapped" within an interface implementation and then instantiated just like any other interface. For example, I might have an RTL implementation of a FIFO. I might want to embed this within an interface implementation that implements write() and read() tasks.
======================================================================
Section 13.1 - Scheduling issues (Stuart/Cadence) [Basic, System]
- interfaces allow non-deterministic behavior due to scheduling order
- need ability to control scheduling order
Interfaces provide plenty of opportunities for users to create non-deterministic designs (i.e. designs whose behavior is dependent on the scheduling order that a particular simulator happens to use.) What are the rules and the capabilities that System Verilog will provide to enable users to create interfaces that do NOT result in non-deterministic designs? For example: Can the user model the equivalent of non-blocking delays & delta cycles within interfaces? Can the user do the equivalent of signal resolution for multiple processes that simultaneously update the state of an interface?
======================================================================
Section 13.2.3 - Interface usage issues (Stuart/Cadence) [Basic, System]
- need to be able to specify and enforce rules about interface usage
- e.g., use of either Read or Write operation but not both
- e.g., limits on number of modules/processes invoking a given interface operation
- should be possible to define such rules in the interface itself without changing other code
- need to check rules in a way that allows for separate compilation
- need to be able to specify that some tasks/members of an interface are private
"Generic" interfaces allow a module to be attached to different interfaces, but they do not convey to the reader or allow tools to enforce that the module must be connected to an interface that implements a specific set of tasks or has specific members. As a simple example, there may be several different interface implementations of a FIFO -- one might gather statistics, another might not. In both cases modules that might be connected to such FIFOs should have an interface declaration that clearly specifies the set of FIFO operations that must be supported. E.g. write() but NOT read(), or vice-versa. Given the current proposed scheme, it can only be determined at elaboration-time whether an interface binding in a particular case is legal or not. Instead I believe it ought to be possible to determine this legality at the time a single module or interface is compiled.
It should be possible to do port registration checks for interfaces. For example, a user might want to implement a FIFO interface that enforces that it has exactly one module or process that writes to it, and exactly one module or process that reads from it. It should be possible for the designer to create such checks only within the interface, without forcing the code within modules attached to the interface to be modified.
In SystemVerilog today all tasks and members of an interface are available to be used by modules attached to the interface. This will inevitably lead to designs or models that use tasks or members of an interface that were never intended to be used externally. Therefore I believe that it should be possible to make certain tasks and members private so that they cannot be accessed externally.
======================================================================
Section 13.4 - Modports issues (Stuart/Cadence) [Basic, System]
- allow modports to be declared outside of interface/module, for reuse
- allow (modules and) interfaces to specify which modport(s) they implement
- import/export is confusing and unnecessary
It appears that Modports can only be declared within an interface. Why not allow modports to be declared outside of interfaces and modules, so that more than one interface implementation can implement the same modport? This would be a less error-prone solution than "generic interfaces".
The use of "import/export" within Modports is confusing and unnecessary. Instead I believe that modports should be declared separately from interfaces, and the tasks that a modport makes available should be declared within the modport. Then when an interface is to implement the tasks of a modport, it explicitly indicates this via a "implements mod_port_name" construct. Similarly, since I believe that modules and interfaces should be equivalent, a module that wishes to make tasks available to other modules or interfaces will simply specify that it "implements some_mod_port_name".
Modules and interfaces should be able to implement multiple modports.
======================================================================
Section 13.5.4 - Issue with extern forkjoin task (Stuart/Cadence) [Basic, System]
- not necessary (at least for the example)
- unnecessarily inefficient - there are better methods
"Extern forkjoin tasks" capability is highly specialized and unnecessarily inefficient. A much better approach to modeling the example within this section is to have the simple_bus be aware of the address map for the slaves attached to the bus -- then only the slave responsible for a particular address needs to be activated for any request. This would allow us to get rid of the "extern forkjoin task" construct altogether and have a much more straightforward and efficient solution.
This archive was generated by hypermail 2b28 : Tue Jun 11 2002 - 08:46:37 PDT