the problem with packages and generics and user defined types(arrays, records, etc)

Discussion in 'VHDL' started by wallge, Feb 8, 2008.

  1. wallge

    wallge Guest

    So here's my problem - and it is starting to drive me really crazy as
    I start to become a seasoned VHDL designer.

    I have lots of modules I have designed - and many of them have their
    own associated packages to define some types that are used inside of
    them, as well as constants that may be pertinent to each component's
    functioning.

    Consequently, anytime I want to instantiate components in the design I
    am using, I wind up having to drag along a bunch of packages - that
    occasionally have contradictory type definitions or constants that
    wind up making up a bunch of work for me when I go to plug everything
    together.

    So I decided that I would like to use generics for each component
    instead of packages.
    The problem with this (as far as I can tell) is that you can't pass
    types

    (eg. array_type is array (3 downto 0) of unsigned(7 downto 0))

    as generics.
    You have to have a package in order to use any user defined types that
    are shared (maybe used as ports) between multiple entities.

    What I would like is a way of sharing custom type definitions between
    multiple entities
    -- where they type definitions would be based on generics passed to
    the component
    when it is instantiated, without having to having to keep track of a
    bunch of packages.

    Does anyone have a solution to this problem?

    thanks in advance.
    wallge, Feb 8, 2008
    #1
    1. Advertising

  2. wallge

    KJ Guest

    On Feb 8, 1:00 pm, wallge <> wrote:
    > I have lots of modules I have designed - and many of them have their
    > own associated packages to define some types that are used inside of
    > them, as well as constants that may be pertinent to each component's
    > functioning.
    >

    OK.

    > Consequently, anytime I want to instantiate components in the design I
    > am using, I wind up having to drag along a bunch of packages - that
    > occasionally have contradictory type definitions or constants that
    > wind up making up a bunch of work for me when I go to plug everything
    > together.
    >

    Just what do you mean by 'contradictory type definitions or
    constants'? Reusing the same type name or constant names in multiple
    packages? If so, then you can use the 'path name' to the thing in
    question.

    Example:
    Instead of...
    use pkg_this_package.all;
    use pkg_that_package.all;
    ...
    signal abc : my_type;
    signal xyz : my_type;

    you can have (note: no need for 'use' statements)
    signal abc : work.pkg_this_package.my_type;
    signal xyz : work.pkg_that_package.my_type;

    Constants as well can be referred to similarly

    constant ZZZ: integer := work.pkg_this_package.some_const;

    Again, I'm not sure if this is the type of issue you're running across
    or not.

    > So I decided that I would like to use generics for each component
    > instead of packages.
    > The problem with this (as far as I can tell) is that you can't pass
    > types
    >
    > (eg. array_type is array (3 downto 0) of unsigned(7 downto 0))
    >

    You're correct, you can not do this.

    > as generics.
    > You have to have a package in order to use any user defined types that
    > are shared (maybe used as ports) between multiple entities.
    >

    Sharing between entities is the only reason you would put it in the
    package to begin with. Any other 'local' constants would be put in
    the architecture or process body.

    > What I would like is a way of sharing custom type definitions between
    > multiple entities
    > -- where they type definitions would be based on generics passed to
    > the component
    > when it is instantiated, without having to having to keep track of a
    > bunch of packages.
    >
    > Does anyone have a solution to this problem?
    >

    I don't think there is a solution along the lines of thinking that
    you're proposing.

    Kevin Jennings
    KJ, Feb 8, 2008
    #2
    1. Advertising

  3. wallge wrote:
    ....
    > Consequently, anytime I want to instantiate components in the design I
    > am using, I wind up having to drag along a bunch of packages - that
    > occasionally have contradictory type definitions or constants that
    > wind up making up a bunch of work for me when I go to plug everything
    > together.


    I agree with KJ.
    Type and constant declarations should be left
    in process or architecture scope unless they
    are related to the top ports, or custom functions.

    If a declaration is packaged, it should be well-named.
    Identifiers like count, state, i, n etc. should be locals.

    > So I decided that I would like to use generics for each component
    > instead of packages.


    I would stick with packages, but tidy them up.
    Sometimes I cut and paste exactly what I need
    into one package for each significant synthesis entity.


    -- Mike Treseler
    Mike Treseler, Feb 8, 2008
    #3
  4. wallge

    wallge Guest

    On Feb 8, 3:03 pm, Mike Treseler <> wrote:
    > wallge wrote:
    >
    > ...
    >
    > > Consequently, anytime I want to instantiate components in the design I
    > > am using, I wind up having to drag along a bunch of packages - that
    > > occasionally have contradictory type definitions or constants that
    > > wind up making up a bunch of work for me when I go to plug everything
    > > together.

    >
    > I agree with KJ.
    > Type and constant declarations should be left
    > in process or architecture scope unless they
    > are related to the top ports, or custom functions.



    Typically, the problem is that I have custom types
    (records, arrays, etc) that are used as ports.
    The definition of these types is done in a package.
    This allows the various entities that use the
    custom types as ports to connect to one another.
    The thing is, I don't want to have to have to
    keep track of ,say, 10 different packages
    when putting a design together - typically
    I have to edit several of the package definitions
    in order to make everything agree, and if
    I forget one here or there, the design won't
    compile.

    What I really want is a kind of functionality
    similar to C++ template classes, where you can
    pass a custom type as a generic.
    This would make maintaining and reusing the code
    a much cleaner and easier process.



    >
    > If a declaration is packaged, it should be well-named.
    > Identifiers like count, state, i, n etc. should be locals.
    >
    > > So I decided that I would like to use generics for each component
    > > instead of packages.

    >
    > I would stick with packages, but tidy them up.
    > Sometimes I cut and paste exactly what I need
    > into one package for each significant synthesis entity.
    >
    > -- Mike Treseler
    wallge, Feb 9, 2008
    #4
  5. wallge

    KJ Guest

    Re: the problem with packages and generics and user defined types (arrays, records, etc)

    "wallge" <> wrote in message
    news:...
    > On Feb 8, 3:03 pm, Mike Treseler <> wrote:
    >> wallge wrote:
    >>
    >> ...
    >>
    >> > Consequently, anytime I want to instantiate components in the design I
    >> > am using, I wind up having to drag along a bunch of packages - that
    >> > occasionally have contradictory type definitions or constants that
    >> > wind up making up a bunch of work for me when I go to plug everything
    >> > together.

    >>
    >> I agree with KJ.
    >> Type and constant declarations should be left
    >> in process or architecture scope unless they
    >> are related to the top ports, or custom functions.

    >
    >
    > Typically, the problem is that I have custom types
    > (records, arrays, etc) that are used as ports.
    > The definition of these types is done in a package.


    That's the correct place for it.

    > This allows the various entities that use the
    > custom types as ports to connect to one another.
    > The thing is, I don't want to have to have to
    > keep track of ,say, 10 different packages
    > when putting a design together


    You lost me on just what it is that you're keeping track of. In order to
    use the entities and packages you simply include the files into the project
    one time.

    > - typically
    > I have to edit several of the package definitions
    > in order to make everything agree, and if
    > I forget one here or there, the design won't
    > compile.
    >


    Well if you have to edit package definitions in order to get things to agree
    then there seems to be a problem with how you're defining things in those
    packages. Each package 'should' be either
    - Completely stand alone (i.e. dependent on no other packages)
    - Or only dependent on standard packages (i.e. like ieee.std_logic_1164,
    ieee.numeric_std, etc.)
    - Or at most dependent on some package of common things that you can reuse
    on most any project (i.e pkg_vhd_common). The file that contains
    pkg_vhd_common would be compiled first (or at least very early since it is
    so 'common').

    pkg_vhd_common (my name, not any standardized name) would contain things
    that you build up over time as things that you frequently use from project
    to project but never change (other than to add additional useful things as
    you work them out).

    > What I really want is a kind of functionality
    > similar to C++ template classes, where you can
    > pass a custom type as a generic.


    That would be handy but it's not there with VHDL. If this is the gist of
    what you're getting at as far as the package edits and editing then I
    certainly agree that in certain situations, a class template would be a
    handy thing but you can also do a surprising amount without it.

    One fairly trivial but easy example to understand just for discussion
    purposes would be the simple fifo. Let's say you start by writing and
    debugging the code for a fifo that works only with std_ulogic_vectors. On
    some subsequent project you want to put integers, or some record type or
    whatever into a fifo. Now you're stuck with having to create a new fifo
    (presumably based on your already written std_ulogic_vector fifo and doing
    copy/paste/edit) that handles integers or the new record type whereas if
    VHDL had class template type of notation you wouldn't since the type
    information would be passed in.

    But now consider an approach where you define functions that convert from
    your custom type into (or back from) std_ulogic_vectors. Something like
    function to_std_ulogic_vector(L: my_type) return std_ulogic_vector
    function from_std_ulogic_vector(L: std_ulogic_vector) return my_type

    Now you can interface to your already written, debugged and working fifo
    component by using these conversion functions and it is only costing you two
    lines of code of typing (the declaration of a signal to use for the fifo
    data output and the line that converts that signal into the type that you
    really want it to be).

    signal Fifo_Out_sulv: std_ulogic_vector(...);
    signal Fifo_Out_my_type: my_type;
    ....
    Fifo_Of_My_Type : my_sulv_fifo
    generic map(
    width => Fifo_Out_sulv'length,
    ...
    port map(
    Data_In => to_std_ulogic_vector(Fifo_In_My_Type),
    Data_Out => Fifo_Out_sulv,
    ...
    );

    Fifo_Out_my_type <= from_std_logic_vector(Fifo_Out_sulv);

    From a synthesis standpoint the to/from conversion functions costs 0 logic
    since they are generally just fancy ways of renaming signals.

    So by simply deciding on a basic type that you will generally be designing
    from (i.e. std_ulogic_vector in this example) and providing functions to
    convert to/from this type from any new type that you create you've created
    most of the capability that could come from a class template. Note that the
    proper place for these to/from conversion functions is in the package that
    defines the new type not in the fifo package (in this example).

    By having only one (or at most very few) basic design types you'll have very
    few conversion functions that need to be created with each new type but most
    important your already written and working packages won't need to expand
    later on as you try to reuse them because you won't be expanding on the
    basic design types that you use at the most fundamental level.

    The function names that you use you should standardize on as well
    (to_std_ulogic_vector and from_std_ulogic_vector in this case). All of your
    new types will create functions with these same names (function overloading
    is supported in VHDL). That way when you go to use these functions, the
    compiler will figure out the appropriate function to use based on the
    argument and return types whereas you as the designer can simply type
    'to_std_ulogic_vector(Sig_Of_My_Type)' without banging your head trying to
    remember what type the signal is.

    There are some places where this approach breaks down a bit but maybe this
    is along the lines of what you're looking for

    > This would make maintaining and reusing the code
    > a much cleaner and easier process.
    >


    I've found the approach I described above to be clean and easy to understand
    and it does not incur any synthesis penalties (i.e. extra logic) either.

    Kevin Jennings
    KJ, Feb 9, 2008
    #5
  6. wallge wrote:

    > I have to edit several of the package definitions
    > in order to make everything agree, and if
    > I forget one here or there, the design won't
    > compile.


    I use emacs vhdl-generate-makefile and vhdl-make
    to work out the compilation dependencies in project files.
    KJ has covered the elimination of dependency loops.

    > What I really want is a kind of functionality
    > similar to C++ template classes, where you can
    > pass a custom type as a generic.


    Me too. Ada has it, vhdl doesn't.
    Something like KJ's functional type conversions
    could be built into the language if anyone
    had the time and money. However, just as it
    is today, vhdl beats the verilogs and the
    vendor wizards on practical abstractions
    for fpga synthesis.

    -- Mike Treseler
    Mike Treseler, Feb 9, 2008
    #6
  7. Re: the problem with packages and generics and user defined types (arrays, records, etc)

    wallge wrote:

    > The problem with this (as far as I can tell) is that you can't pass
    > types
    >
    > (eg. array_type is array (3 downto 0) of unsigned(7 downto 0))
    >
    > as generics.


    Not that it is going to solve your problem right away, but in VHDL-200X
    (VHDL-2008) you can pass types as generics. Also packages can have
    generics. See http://www.synthworks.com/papers/index.htm, first paper
    (Accellera VHDL 2006 Standard 3.0). Also google on VHDL-2008.

    --
    Paul Uiterlinden
    www.aimvalley.nl
    e-mail addres: remove the not.
    Paul Uiterlinden, Feb 11, 2008
    #7
  8. wallge

    Andy Guest

    On Feb 9, 10:53 am, "KJ" <> wrote:
    > "wallge" <> wrote in message
    >
    > news:...
    >
    >
    >
    > > On Feb 8, 3:03 pm, Mike Treseler <> wrote:
    > >> wallge wrote:

    >
    > >> ...

    >
    > >> > Consequently, anytime I want to instantiate components in the design I
    > >> > am using, I wind up having to drag along a bunch of packages - that
    > >> > occasionally have contradictory type definitions or constants that
    > >> > wind up making up a bunch of work for me when I go to plug everything
    > >> > together.

    >
    > >> I agree with KJ.
    > >> Type and constant declarations should be left
    > >> in process or architecture scope unless they
    > >> are related to the top ports, or custom functions.

    >
    > > Typically, the problem is that I have custom types
    > > (records, arrays, etc) that are used as ports.
    > > The definition of these types is done in a package.

    >
    > That's the correct place for it.
    >
    > > This allows the various entities that use the
    > > custom types as ports to connect to one another.
    > > The thing is, I don't want to have to have to
    > > keep track of ,say, 10 different packages
    > > when putting a design together

    >
    > You lost me on just what it is that you're keeping track of. In order to
    > use the entities and packages you simply include the files into the project
    > one time.
    >
    > > - typically
    > > I have to edit several of the package definitions
    > > in order to make everything agree, and if
    > > I forget one here or there, the design won't
    > > compile.

    >
    > Well if you have to edit package definitions in order to get things to agree
    > then there seems to be a problem with how you're defining things in those
    > packages. Each package 'should' be either
    > - Completely stand alone (i.e. dependent on no other packages)
    > - Or only dependent on standard packages (i.e. like ieee.std_logic_1164,
    > ieee.numeric_std, etc.)
    > - Or at most dependent on some package of common things that you can reuse
    > on most any project (i.e pkg_vhd_common). The file that contains
    > pkg_vhd_common would be compiled first (or at least very early since it is
    > so 'common').
    >
    > pkg_vhd_common (my name, not any standardized name) would contain things
    > that you build up over time as things that you frequently use from project
    > to project but never change (other than to add additional useful things as
    > you work them out).
    >
    > > What I really want is a kind of functionality
    > > similar to C++ template classes, where you can
    > > pass a custom type as a generic.

    >
    > That would be handy but it's not there with VHDL. If this is the gist of
    > what you're getting at as far as the package edits and editing then I
    > certainly agree that in certain situations, a class template would be a
    > handy thing but you can also do a surprising amount without it.
    >
    > One fairly trivial but easy example to understand just for discussion
    > purposes would be the simple fifo. Let's say you start by writing and
    > debugging the code for a fifo that works only with std_ulogic_vectors. On
    > some subsequent project you want to put integers, or some record type or
    > whatever into a fifo. Now you're stuck with having to create a new fifo
    > (presumably based on your already written std_ulogic_vector fifo and doing
    > copy/paste/edit) that handles integers or the new record type whereas if
    > VHDL had class template type of notation you wouldn't since the type
    > information would be passed in.
    >
    > But now consider an approach where you define functions that convert from
    > your custom type into (or back from) std_ulogic_vectors. Something like
    > function to_std_ulogic_vector(L: my_type) return std_ulogic_vector
    > function from_std_ulogic_vector(L: std_ulogic_vector) return my_type
    >
    > Now you can interface to your already written, debugged and working fifo
    > component by using these conversion functions and it is only costing you two
    > lines of code of typing (the declaration of a signal to use for the fifo
    > data output and the line that converts that signal into the type that you
    > really want it to be).
    >
    > signal Fifo_Out_sulv: std_ulogic_vector(...);
    > signal Fifo_Out_my_type: my_type;
    > ...
    > Fifo_Of_My_Type : my_sulv_fifo
    > generic map(
    > width => Fifo_Out_sulv'length,
    > ...
    > port map(
    > Data_In => to_std_ulogic_vector(Fifo_In_My_Type),
    > Data_Out => Fifo_Out_sulv,
    > ...
    > );
    >
    > Fifo_Out_my_type <= from_std_logic_vector(Fifo_Out_sulv);
    >
    > From a synthesis standpoint the to/from conversion functions costs 0 logic
    > since they are generally just fancy ways of renaming signals.
    >
    > So by simply deciding on a basic type that you will generally be designing
    > from (i.e. std_ulogic_vector in this example) and providing functions to
    > convert to/from this type from any new type that you create you've created
    > most of the capability that could come from a class template. Note that the
    > proper place for these to/from conversion functions is in the package that
    > defines the new type not in the fifo package (in this example).
    >
    > By having only one (or at most very few) basic design types you'll have very
    > few conversion functions that need to be created with each new type but most
    > important your already written and working packages won't need to expand
    > later on as you try to reuse them because you won't be expanding on the
    > basic design types that you use at the most fundamental level.
    >
    > The function names that you use you should standardize on as well
    > (to_std_ulogic_vector and from_std_ulogic_vector in this case). All of your
    > new types will create functions with these same names (function overloading
    > is supported in VHDL). That way when you go to use these functions, the
    > compiler will figure out the appropriate function to use based on the
    > argument and return types whereas you as the designer can simply type
    > 'to_std_ulogic_vector(Sig_Of_My_Type)' without banging your head trying to
    > remember what type the signal is.
    >
    > There are some places where this approach breaks down a bit but maybe this
    > is along the lines of what you're looking for
    >
    > > This would make maintaining and reusing the code
    > > a much cleaner and easier process.

    >
    > I've found the approach I described above to be clean and easy to understand
    > and it does not incur any synthesis penalties (i.e. extra logic) either.
    >
    > Kevin Jennings


    Ahhh, type conversions on ports...

    Beware of problems when the ports are of unconstrained types. In such
    cases, the conversion function must return (or accept as in the case
    of a conversion on an out or inout port) a constrained type. The width
    of an unconstrained port is obtained from the width of the associated
    actual, which is unknown in the case of a conversion function that
    returns an unconstrained type.

    For instance

    data_in => to_slv(my_data);

    to_slv() must return a specific length slv if data_in is declared as
    an unconstrained slv.

    For output mode ports:

    to_my_type(data_out) => my_data_out;

    has the same restriction, but on the argument of to_my_type(), not the
    result.

    Finally, for bidirectional ports:

    to_my_type(data_io) => to_slv(my_data_io);

    Keep in mind that type conversion functions also work in configuration
    port maps.

    Andy
    Andy, Feb 12, 2008
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Debo
    Replies:
    3
    Views:
    606
    Swampmonster
    Dec 12, 2004
  2. Oodini
    Replies:
    1
    Views:
    1,750
    Keith Thompson
    Sep 27, 2005
  3. Kevin Walzer

    Re: PIL (etc etc etc) on OS X

    Kevin Walzer, Aug 1, 2008, in forum: Python
    Replies:
    4
    Views:
    370
    Fredrik Lundh
    Aug 13, 2008
  4. Mark_Galeck
    Replies:
    1
    Views:
    763
    Knute Johnson
    Oct 26, 2008
  5. Rob Gaddi

    Generics, packages, and VHDL-2008

    Rob Gaddi, May 9, 2013, in forum: VHDL
    Replies:
    5
    Views:
    380
    Rob Gaddi
    May 16, 2013
Loading...

Share This Page