On Feb 9, 10:53 am, "KJ" <
[email protected]> wrote:
> "wallge" <
[email protected]> wrote in message
>
> news:
[email protected]...
>
>
>
> > On Feb 8, 3:03 pm, Mike Treseler <
[email protected]> 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