Subject: Re: [vhdl-200x-dta] White paper on type generics
From: Jim Lewis (Jim@SynthWorks.com)
Date: Tue Nov 11 2003 - 16:57:05 PST
Peter,
I have read (and re-read) the type genericity paper
enough now that I will attempt to comment. The concepts
in Peter's paper are outstanding, and I would recommend
that all read them if you are not already familiar with
SUAVE.
Note about my comments, I am much more of a design engineer
than I am a language designer, so expect me to make a
few blunders and please bear with me.
Section 2 Generic Packages
The placement of the generic clause in the syntax
troubles me a little. I think "IS" should follow the
generic clause (separating it from the declarations)
similar to how a procedure is declared (rather than
being similar to an entity/component):
package floating_matrix_IO
generic (
type matrix is array ;
type matrix_file is file
) is
package_declaration ::=
package identifier
[ formal_generic_clause ]
is
package_declarative_part
end [ package ] [ package_simple_name ] ;
I guess if I ever used the entity declarative region it would bother me
the same way.
Section 3 Generic Subprograms
Why add a keyword named parameter rather than use a keyword
named port? Port seems more consistent with entity, block,
and processes (from SUAVE).
I like having the keyword and I like making it optional as long
as it remains optional even when a generic clause is present.
I think this proposal respects both those who value
conciseness and those who value the longer more verbose
form.
Perhaps this would give us cause to make the port
keyword on entities (and blocks and processes) optional
and further make port map optional. If we could make
port map optional, one could swap between a concurrent
subprogram call and a component instantiation by referencing
either a package that contains component declarations
or a package that contains subprogram definitions.
Section 5: Extended Generic Clauses
The proposed syntax is inconsistent with signal, file,
constant, and variable IO:
generic ( type element_type is private );
It seems like something like the following would be
consistent with other existing generics:
generic ( type element_type : private );
Note this does not make sense if we cannot simplify the syntax for
formal array types, formal record types (just guessing), formal file types,
formal generic subprograms, and formal generic packages.
The one that troubles me most is formal generic subprograms.
Section 6 Formal Generic types.
My perspective on types is based on my RTL design and
verification background. For RTL design, the primary types used
are: std_logic, std_logic_vector, unsigned, and signed.
In the future, I expect there to be numeric array types for
fixed point and floating point arithmetic.
For verfication, I also use records. I would use integers
in the records if we extend records like the modports of
SystemVerilog's interfaces.
Can I use "+" operators when I pass the type unsigned or
signed? What if the package numeric_std were visible
to the generic package? What if numeric_std were visible
at the point of instantiation of the pacakge? What if I
pass the package numeric_std to the package?
I am guessing that none of the above work (otherwise,
why have formal integer types). I think having generic
packages that allow types signed and unsigned to be mapped
to them is important. In addition, I
expect the future to also include array based types for
fixed point and floating point arithmetic.
Section 6.1 Formal Private Types
Can I pass std_logic_vector as a private type?
In the example in section 6.1, this would make element_node
a record with an unconstrained array. Not currently
supported, but I think this would be a good thing to support.
This feature is a great addition and would allow some
very powerful standard packages to be written to support
a number of verification features.
Section 6.2 Formal Discrete Types
This is a neat feature, but not useful to me.
Keep in mind, for design, the types we use are
primarily array types.
Request: Remove paretheses around <> or make them optional.
In section 6.2 they seem to be required, but in the other
sections, 6.3, 6.4 they are left off of the syntax there.
From 6.4:
package product_measures is
generic ( type measure1, measure2 is units <> );
Section 6.3 Formal Integer Types
See comments for 6.2.
Integer is not useful since there is no
implicit mapping to bits (it would need to be the same
every time too).
Can we make this Formal Numeric Types? Sure would be
great to include unsigned and signed (as well as the
future/in progress proposals for fixed point and floating
point array types).
I don't think I should need generics to make this example
work. I do need some extensions to the type attributes and
range attributes that I applied to the data objects in the
example below. Note I made a minor correction (?)
to the increment algorithm (which I think was accidentally
reversed or needed /=).
entity counter is
port( clk : in bit ; data : out integer );
end entity counter ;
architecture behavioral of counter is
begin
count_behavior : process is
variable count : integer range data'range := data'low;
begin
data <= count;
wait until clk = '1';
if count = count'high then
count := count'low; -- reset on reaching max count
else
count := count + 1; -- otherwise increment
end if;
end process count_behavior;
end architecture behavioral;
entity testbench is
end testbench ;
architecture a1 of testbench is
signal Clk : bit := '0' ;
signal data : integer range 0 to 255 ;
component counter is
port( clk : in bit ; data : out integer );
end component counter ;
begin
Clk <= not Clk after 20 ns ;
U_Counter : counter
port map ( Clk, Data) ;
end a1 ;
Section 6.4 Formal Physical types
See comments for 6.2.
The number of packages we are currently working
with is getting out of hand. Some of the examples in
this section demonstrate this quite well.
This leads me to ask for one (or two) of three potential
features:
Alternate 1) Allow package instantiation to extend a package:
package power_measures is new work.product_measure
generic map ( measure1 => voltage, measure2 => current )
begin
alias power is work.power_measures.product_measure;
alias pW is work.power_measures.product_unit;
alias nW is work.power_measures.product_unit_E3;
alias uW is work.power_measures.product_unit_E6;
alias mW is work.power_measures.product_unit_E9;
alias W is work.power_measures.product_unit_E12;
end package power_measures;
Alternate 2) Super Package: Package instantiation
in another package is as if the package contents were
declared locally:
package power_measures is
package is new work.product_measure -- nameless instantiation
generic map ( measure1 => voltage, measure2 => current ) ;
alias power is work.power_measures.product_measure;
alias pW is work.power_measures.product_unit;
alias nW is work.power_measures.product_unit_E3;
alias uW is work.power_measures.product_unit_E6;
alias mW is work.power_measures.product_unit_E9;
alias W is work.power_measures.product_unit_E12;
end package power_measures;
Alternate 3) Super Package/context clause:
Create a design unit that contains library clauses,
package references, and package instantiations
(subprogram instantiations). Referencing this
design unit before an entity is as if the contents
were placed in-line before the entity declaration
(note packages could be given this functionality):
In terms of this proposal, currently we have a
default context for all entities which consists of:
Context default_context is
library std ;
use std.standard.all ;
library work ;
end context default_context ;
Allow the default_context to be extended by compiling
it into the library work:
Context default_context is
library std ;
use std.standard.all ;
library work ;
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
use std.textio.all ;
end context default_context ;
Allow other contextes to be compiled into a library and
referenced with a use clause:
use work.my_context ;
Furthermore, it would also be interesting if the context
had a interface space (the whole thing if not specified)
and a local space (for things that do not apply to the
interface, but it is convenient to collect them here
anyway). The local space would only apply to secondary
units such as the architecture.
Section 6.5 Formal Floating Types
See comments for 6.3.
For floating point types to be useful, we need a
way to size exponent and mantissa for hardware.
In addition, like integers, we need an exact way to
map the floating point number to bits.
Section 6.6 Formal Array Types
I would definitely use this.
One thing VHDL needs is a component library in some ways
that is similar to the 74 series board parts. Sure would
be handy to write it once for arrays in general and
then instantiate versions for std_logic_vector, signed,
and unsigned.
Syntax seems a little heavy. How much type information
do we need to pass and how much can we extract from
the environment? Current entity interface for example in 6.6:
entity shift_register is
generic (
type index_type is (<>);
type element_type is private;
type vector is array ( index_type range <> ) of element_type
);
port (
clk : in bit;
data_in : in element_type;
data_out : out vector );
end entity shift_register ;
Lets add two attributes of array types:
element_type returns the element type of the array
index_type returns the type of the index type of the array.
Can we reduce and perhaps simplify the array syntax to the following:
entity shift_register is
generic ( type vector is array );
port (
clk : in bit;
data_in : in vector'element_type;
data_out : out vector );
end entity shift_register ;
architecture behavioral of shift_register is
begin
shift_behavior : process is
constant data_low : vector'index_type := data_out’low;
constant data_high : vector'index_type := data_out’high;
-- type ascending_vector is array ( data_low to data_high ) of element_type; -- if used, forces a type caste
variable stored_data : vector(data_low to data_high);
begin
data_out <= stored_data; -- data_out <= vector(stored_data) ; -- required if use ascending_vector
wait until clk = ’1’;
stored_data := stored_data(data_low to index_type’pred(data_high)) & data_in ;
end process shift_behavior;
end architecture behavioral;
Currently synthesis tools do not like unconstrained arrays at entity
interfaces, so to make them a little more happy:
entity shift_register is
generic (
type vector is array ;
constant width : integer :=8
);
port (
clk : in bit;
data_in : in vector'base_type;
data_out : out vector((width - 1) downto 0 );
end entity shift_register ;
Note, if we keep the original example in 6.6, stored_data
is of type ascending_vector and data_out is of type vector.
Hence, don't they require an implicit type conversion (type
caste)?
data_out <= vector(stored_data) ;
In addition, is it ok to use concatenation "&" (as shown
above in my modified example) rather than slicing as shown
in the example in 6.6?
6.7 Formal Record Types
Probably would want to use this feature for testbenches.
Probably would want a simplied syntax similar to what
I proposed for arrays.
6.8 Formal Access Types
Probably would want to use this feature for testbenches.
Simplifying the generics as proposed in 6.6
procedure copy_vector
generic (
type vector is array ;
type vector_ptr is access vector
) ;
port ( src : in vector_ptr; dest : inout vector_ptr ) is
begin . . .
6.9 Formal File Types
Like arrays I would like to see a simplified generic format:
package floating_matrix_IO is
generic (
type matrix is array ;
type matrix_file is file
);
There is a comment in this section that states:
"The package cannot be written with a private type for the
element type, since there are restrictions on the kinds of
types that can be included as file elements."
I understand the comment. However, for things like printing
it bothers me. Can we define a set of functions/procedures
which would be required to be defined for all ieee packages
so that we don't have a restriction like this for something
basic like printing.
7 Formal Generic Subprograms
I like it. I just wish I did not have to have
an entire subprogram specification in the generic.
Also leads to another interesting question.
For a record, is there a way to specify an
element field, such as tree_record.left_subtree
in a call? What I am thinking is rather than
writing separate functions for traverse
right subtree and traverse left subtree,
I could write a general traverse branch and
specify which record element has the appropriate
branch to traverse.
8 Formal Generic Packages
It seems odd to instantiate a generic package in a generic.
Passing packages seems to be normal, but not instantiating
a generic package in the interface.
What seems more natural to me is to pass generic values for
the generic package instantiation and instantiate the package
inside the package. See my comments following section 6.4 under
alternate 2 for an example of what I am thinking.
As a final note, I think this stuff is good. To be really great,
we need to be able to do more with std_logic_vector, signed, and
unsigned. Maybe this capability is there and I just don't see
it.
Cheers,
Jim
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Jim Lewis Director of Training mailto:Jim@SynthWorks.com SynthWorks Design Inc. http://www.SynthWorks.com 1-503-590-4787Expert VHDL Training for Hardware Design and Verification ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Peter Ashenden wrote:
> Dear colleages, > > Attached is a draft white paper on a proposed extension to VHDL for type > generics. The extension will provide a mechanism for specifying > type-parameterized data types, such as queues, lists, sets, etc. It will > also allow for type-parameterized design entities. > > Looking forward to your comments. > > Cheers, > > PA > > -- > Dr. Peter J. Ashenden peter@ashenden.com.au > Ashenden Designs Pty. Ltd. www.ashenden.com.au > PO Box 640 Ph: +61 8 8339 7532 > Stirling, SA 5152 Fax: +61 8 8339 2616 > Australia Mobile: +61 414 70 9106
This archive was generated by hypermail 2b28 : Tue Nov 11 2003 - 16:57:30 PST