Generics vs Constants - what criteria do you use to choose between these?

Discussion in 'VHDL' started by Andrew FPGA, Oct 4, 2006.

  1. Andrew FPGA

    Andrew FPGA Guest

    Hi all,
    I often find myself implementing a piece of functionality whose
    behaviour I want to control using either a Generic or a constant. But
    sometimes I'm not sure if a generic or a constant is the best approach.
    By "best" approach I mean the style which gives the best tradeoff in
    flexibility of design, ease of understanding the design, and ease of
    use by grouping these "build functionality modifiers". What criteria
    do others use when choosing between the use of a generic or a constant
    in their design?

    Quick example: Say I have some debug code (say a PRBS generator) that I
    only want included in the design for debug builds. For the production
    release I don't want the functionality there. I would use a generate
    statement around the PRBS generator. Then I could
    a) have a Generic on the module in which this PRBS generator exists
    called "INCLUDE_PRBS_GENERATOR : boolean" . Whenever this module is
    instantiated I can choose to build with or without the PRBS generator.
    b) I could have a constant INCLUDE_PRBS_GENERATOR. That constant can be
    set to true/false within the module or could be put into a package
    collecting together all build options in one place.

    Advantages of the generic approach:
    1) Each instantiation of the module can be customised differently to
    the others.
    2) ?

    Advantages of the constant approach:
    1) All build options can be packaged up in one place, not scattered
    throughout the design hierarchy.
    2) Less typing, don't need to remember to include the generic on every
    instantiation.
    3)?

    Regards
    Andrew
    Andrew FPGA, Oct 4, 2006
    #1
    1. Advertising

  2. Re: Generics vs Constants - what criteria do you use to choose betweenthese?

    Andrew FPGA wrote:

    > Quick example: Say I have some debug code (say a PRBS generator) that I
    > only want included in the design for debug builds. For the production
    > release I don't want the functionality there.


    I would put the generator in the testbench
    if it were not a hardware option.

    For hardware options, I use input port bits
    to set mode options and I let synthesis
    work out the details of generating
    the exact hardware needed for static or dynamic modes.

    I comment out debug assertions in uut code
    once a problem is solved.
    Or I might replace the debug code with
    an explanation of the bug and the fix.

    > Advantages of the generic approach:


    I use generics on a testbench for
    controlling tests from the command line
    using vsim -G.

    A complex design entity usually needs
    a package to share types and constants
    common to the uut and testbench, but
    sometimes I like to set basic port dimensions
    with a generic default on the uut and let the testbench
    ignore it or override the default with
    a generic map.

    > Advantages of the constant approach:


    Packaged types and constants can be shared.

    The downside is, I have to open
    another file to remember the actual
    lengths, enumerations etc.

    -- Mike Treseler
    Mike Treseler, Oct 4, 2006
    #2
    1. Advertising

  3. Andrew FPGA

    KJ Guest

    "Andrew FPGA" <> wrote in message
    news:...
    > Hi all,
    > I often find myself implementing a piece of functionality whose
    > behaviour I want to control using either a Generic or a constant. But
    > sometimes I'm not sure if a generic or a constant is the best approach.
    > By "best" approach I mean the style which gives the best tradeoff in
    > flexibility of design, ease of understanding the design, and ease of
    > use by grouping these "build functionality modifiers". What criteria
    > do others use when choosing between the use of a generic or a constant
    > in their design?

    The basic question that I ask is "If I were to reuse this code in some
    fashion, what things can I pull out and make generics so that I don't have
    to look at the details of the code in order to know how to use it in a
    different application?" Anything not meeting that criteria would be coded
    as a constant, the ones that do I would make generics on the entity.

    > Quick example: Say I have some debug code (say a PRBS generator) that I
    > only want included in the design for debug builds. For the production
    > release I don't want the functionality there. I would use a generate
    > statement around the PRBS generator. Then I could
    > a) have a Generic on the module in which this PRBS generator exists
    > called "INCLUDE_PRBS_GENERATOR : boolean" . Whenever this module is
    > instantiated I can choose to build with or without the PRBS generator.
    > b) I could have a constant INCLUDE_PRBS_GENERATOR. That constant can be
    > set to true/false within the module or could be put into a package
    > collecting together all build options in one place.
    >
    > Advantages of the generic approach:
    > 1) Each instantiation of the module can be customised differently to
    > the others.
    > 2) ?

    2. Design reuse. Since you'll have the RTL anyway you don't give up the
    ability to look at the code again when you're reusing it and suspect
    something isn't working but do you really want to have to get intimately
    involved with every line of code that you (or someone) wrote a while back
    just because you want to reuse it? I don't, I just want to use it, if it
    doesn't work then I'll debug and improve it but jsut right out of the shoot
    I don't care to require myself to know how it works as long as I have some
    confidence that it was designed using sound design practices (which is tough
    to know on anything other than stuff you write yourself).
    3. Productivity. Because of #2, you'll be more productive (i.e. system
    functions implemented per hour) if you can properly parameterize your code.
    If you do a poor job I suppose you're no better off than having not done it
    at all, don't see how it would be worse.

    > Advantages of the constant approach:
    > 1) All build options can be packaged up in one place, not scattered
    > throughout the design hierarchy.

    Don't need to be scattered. Typically when I create an entity with a
    generic parameter, in many cases that generic will percolate it's way up to
    the top level because at any level I mentally ask the question "If I were to
    reuse this code..." and decide whether the generic of some lower level
    entity should be brought up a level. Given that most percolate to the top
    level of the design anyway, then this implies that all of the constants are
    in one place, the top level design file where I then set them as constants
    in that architecture.

    > 2) Less typing, don't need to remember to include the generic on every
    > instantiation.

    Which is handy if you don't think the code will ever need to be modified.
    But ideally you don't really write too much of that 'use it only once' code.
    If you frequently do then maybe you should take a step back and see if there
    really isn't a bigger picture to see.

    One example that I use frequently in FPGA designs are for those things that
    need to generate signals for specific times (for example a timer, or a
    control signal that needs to have a certain pulse width, etc.) I'll have a
    parameter of type time called Clock_Period. This parameter always
    percolates all the way up to the top level since it's only there that you
    can say what the clock period really is....and sometimes you don't know what
    that period is until after you get a feel for what speed your code will run
    at so having a simple constant to change in one file that gets passed down
    as a generic is a big thing. My typical usage of Clock_Period would be
    something like

    entity Foo is generic(Clock_Period: time)
    .....
    architecture RTL of Foo is
    constant T1: 1 us; -- Assuming that T1 itself shouldn't be brought out as a
    generic
    constant T1_Counter: natural range 0 to T1 / Clock_Period;
    begin
    ....
    Define the usual code for a counter for signal T1_Counter that counts from 0
    to T1 / Clock_Period - 1
    end RTL;

    At that top level where the generics are ultimately defined as constants I
    find that there is frequently a bit of interaction between these constants
    (i.e. one is derived from the other in some fashion). That
    interrelationship should 'make sense', when it doesn't it means that you
    probably have some conflicting ideas floating around that you need to get
    resolved. If those constants were buried down in the code you wouldn't be
    as likely to have noticed the conflict in the first place and wouldn't catch
    it until you couldn't get the simulation (or your board) to work correctly.

    By the way, I also don't limit myself to simple scalar type generics like
    'Clock_Period' or integers for defining signal bus widths or booleans for
    including/excluding sections of code. Arrays of some type, record types,
    arrays of record types are very handy at times to use as signals and
    generics....it all depends on how you choose to parameterize the design.
    The better you get at parameterizing your code the more you'll find using
    more than just scalar type generics is a 'good' thing.

    KJ
    KJ, Oct 5, 2006
    #3
  4. Andrew FPGA

    Andy Guest

    I've found a very interesting hybrid approach to managing constant
    design parameters, but let me summarize some pro's and con's of
    constants vs generics.

    Constants can be defined in a global package for the project, and one
    can simply be added anytime a new parameter in some lower level module
    is needed. Constants, so long as they are not deferred, are locally
    static values, and can be used virtually anywhere. But modifying
    constants requires changing source code in a difficult-to-manage way.
    Different sets of constants (say for build vs verification) must be
    managed with separate files that define the same package, and are
    selectively used based on the application (there are no named package
    bodies that can be chosen via configurations, etc., and even if there
    were, it would require deferred constants, which then loses the locally
    static advantage).

    Generics are not locally static, and must be passed down through the
    hierarchy if they are to be centrally managed. However, they can be
    managed within the abilities of vhdl, without resorting to file naming
    slight-of-hand, by instantiation, configuration, and tool command line
    options.

    While there is nothing that can be done to address the non-locally
    static problem of generics, managing their passing through the
    hierarchy can be made easier. By defining a record type in a global
    package which contains elements for each constant required, we can have
    a flexible "handle" by which to pass all the parameters to every level
    with a single generic map association. Whenever a new parameter is
    needed, the record type is changed to add it, the value is set at the
    top (entity, instance, configuration, or tool) and only the lower level
    entity/architecture that needs it is modified to extract it from the
    record.

    The default values for the top level generic can be defined in the
    generic declaration, or by referencing a constant defined in the same
    global package that defined the record type. Either way, the default
    assignments can be overridden by the testbench that instantiates the
    top level entity, by one or more configuration declarations (requiring
    a wrapper around the otherwise top level entity), or by tool command
    line options.

    BTW, I almost always use a ns_per_clk : positive generic to pass clock
    period info for timers, etc. Synopsis used to not be able to specify
    non-integer generics from the command line. I don't know if they can
    today. To get around such a problem with records, the top leve entity
    can have all the separate integer generics declared, and then assemble
    them into a record in the top level architecture, for passing down
    through the hierarchy.

    No matter which method is used (constants or generics), I strongly
    recommend subtyping them to constrain the values to practical limits.
    If a parameter must, say, be a integral power of two, then a concurrent
    assertion statement should verify that at the point of use.

    Comments?

    Andy


    KJ wrote:
    > "Andrew FPGA" <> wrote in message
    > news:...
    > > Hi all,
    > > I often find myself implementing a piece of functionality whose
    > > behaviour I want to control using either a Generic or a constant. But
    > > sometimes I'm not sure if a generic or a constant is the best approach.
    > > By "best" approach I mean the style which gives the best tradeoff in
    > > flexibility of design, ease of understanding the design, and ease of
    > > use by grouping these "build functionality modifiers". What criteria
    > > do others use when choosing between the use of a generic or a constant
    > > in their design?

    > The basic question that I ask is "If I were to reuse this code in some
    > fashion, what things can I pull out and make generics so that I don't have
    > to look at the details of the code in order to know how to use it in a
    > different application?" Anything not meeting that criteria would be coded
    > as a constant, the ones that do I would make generics on the entity.
    >
    > > Quick example: Say I have some debug code (say a PRBS generator) that I
    > > only want included in the design for debug builds. For the production
    > > release I don't want the functionality there. I would use a generate
    > > statement around the PRBS generator. Then I could
    > > a) have a Generic on the module in which this PRBS generator exists
    > > called "INCLUDE_PRBS_GENERATOR : boolean" . Whenever this module is
    > > instantiated I can choose to build with or without the PRBS generator.
    > > b) I could have a constant INCLUDE_PRBS_GENERATOR. That constant can be
    > > set to true/false within the module or could be put into a package
    > > collecting together all build options in one place.
    > >
    > > Advantages of the generic approach:
    > > 1) Each instantiation of the module can be customised differently to
    > > the others.
    > > 2) ?

    > 2. Design reuse. Since you'll have the RTL anyway you don't give up the
    > ability to look at the code again when you're reusing it and suspect
    > something isn't working but do you really want to have to get intimately
    > involved with every line of code that you (or someone) wrote a while back
    > just because you want to reuse it? I don't, I just want to use it, if it
    > doesn't work then I'll debug and improve it but jsut right out of the shoot
    > I don't care to require myself to know how it works as long as I have some
    > confidence that it was designed using sound design practices (which is tough
    > to know on anything other than stuff you write yourself).
    > 3. Productivity. Because of #2, you'll be more productive (i.e. system
    > functions implemented per hour) if you can properly parameterize your code.
    > If you do a poor job I suppose you're no better off than having not done it
    > at all, don't see how it would be worse.
    >
    > > Advantages of the constant approach:
    > > 1) All build options can be packaged up in one place, not scattered
    > > throughout the design hierarchy.

    > Don't need to be scattered. Typically when I create an entity with a
    > generic parameter, in many cases that generic will percolate it's way up to
    > the top level because at any level I mentally ask the question "If I were to
    > reuse this code..." and decide whether the generic of some lower level
    > entity should be brought up a level. Given that most percolate to the top
    > level of the design anyway, then this implies that all of the constants are
    > in one place, the top level design file where I then set them as constants
    > in that architecture.
    >
    > > 2) Less typing, don't need to remember to include the generic on every
    > > instantiation.

    > Which is handy if you don't think the code will ever need to be modified.
    > But ideally you don't really write too much of that 'use it only once' code.
    > If you frequently do then maybe you should take a step back and see if there
    > really isn't a bigger picture to see.
    >
    > One example that I use frequently in FPGA designs are for those things that
    > need to generate signals for specific times (for example a timer, or a
    > control signal that needs to have a certain pulse width, etc.) I'll have a
    > parameter of type time called Clock_Period. This parameter always
    > percolates all the way up to the top level since it's only there that you
    > can say what the clock period really is....and sometimes you don't know what
    > that period is until after you get a feel for what speed your code will run
    > at so having a simple constant to change in one file that gets passed down
    > as a generic is a big thing. My typical usage of Clock_Period would be
    > something like
    >
    > entity Foo is generic(Clock_Period: time)
    > ....
    > architecture RTL of Foo is
    > constant T1: 1 us; -- Assuming that T1 itself shouldn't be brought out as a
    > generic
    > constant T1_Counter: natural range 0 to T1 / Clock_Period;
    > begin
    > ...
    > Define the usual code for a counter for signal T1_Counter that counts from 0
    > to T1 / Clock_Period - 1
    > end RTL;
    >
    > At that top level where the generics are ultimately defined as constants I
    > find that there is frequently a bit of interaction between these constants
    > (i.e. one is derived from the other in some fashion). That
    > interrelationship should 'make sense', when it doesn't it means that you
    > probably have some conflicting ideas floating around that you need to get
    > resolved. If those constants were buried down in the code you wouldn't be
    > as likely to have noticed the conflict in the first place and wouldn't catch
    > it until you couldn't get the simulation (or your board) to work correctly.
    >
    > By the way, I also don't limit myself to simple scalar type generics like
    > 'Clock_Period' or integers for defining signal bus widths or booleans for
    > including/excluding sections of code. Arrays of some type, record types,
    > arrays of record types are very handy at times to use as signals and
    > generics....it all depends on how you choose to parameterize the design.
    > The better you get at parameterizing your code the more you'll find using
    > more than just scalar type generics is a 'good' thing.
    >
    > KJ
    Andy, Oct 9, 2006
    #4
  5. Andy wrote:

    > While there is nothing that can be done to address the non-locally
    > static problem of generics, managing their passing through the
    > hierarchy can be made easier. By defining a record type in a global
    > package which contains elements for each constant required, we can
    > have a flexible "handle" by which to pass all the parameters to
    > every level with a single generic map association. Whenever a new
    > parameter is needed, the record type is changed to add it, the value
    > is set at the top (entity, instance, configuration, or tool) and
    > only the lower level entity/architecture that needs it is modified
    > to extract it from the record.

    [snip]
    > Comments?


    Just one clarification needed.

    Correct me if I'm wrong: I suppose you also declare a signal in the
    package. The type of the signal is the record type. And with a
    concurrent signal assignment in the toplevel architecture you assign
    the toplevel generic to that signal. It is that signal that you use
    (read) at the lower levels. The signal is made visable by a use
    clause at those levels.

    > No matter which method is used (constants or generics), I strongly
    > recommend subtyping them to constrain the values to practical
    > limits. If a parameter must, say, be a integral power of two, then a
    > concurrent assertion statement should verify that at the point of
    > use.


    Couldn't agree more. Although I would use the exponent as generic and
    do the exponentiation (2**generic) where I need it (via a constant so
    it is only compted once).

    --
    Paul.
    Paul Uiterlinden, Oct 9, 2006
    #5
  6. Re: Generics vs Constants - what criteria do you use to choose betweenthese?

    Andy wrote:

    > Generics are not locally static, and must be passed down through the
    > hierarchy if they are to be centrally managed. However, they can be
    > managed within the abilities of vhdl, without resorting to file naming
    > slight-of-hand, by instantiation, configuration, and tool command line
    > options.


    Yes, for a related example, see seed_c below:

    generic (tb_char_g : natural := 8; -- generic length

    --...
    constant msb : natural := tb_char_g -1;
    -- generic

    subtype char_t is unsigned(msb downto 0);
    -- generic type, usually 8 bits

    constant zero_c : char_t := (others => '0');
    -- generic type, usually 8 bits

    constant seed_c : char_t := "100001" + zero_c;
    -- follows wider generic widths

    > Whenever a new parameter is
    > needed, the record type is changed to add it, the value is set at the
    > top (entity, instance, configuration, or tool) and only the lower level
    > entity/architecture that needs it is modified to extract it from the
    > record.


    Very clever.
    Thanks for the posting.

    > Comments?


    Could we trouble you for a simple example?

    -- Mike Treseler
    Mike Treseler, Oct 9, 2006
    #6
  7. Andrew FPGA

    Andy Guest

    Paul Uiterlinden wrote:
    > Andy wrote:
    >
    > > While there is nothing that can be done to address the non-locally
    > > static problem of generics, managing their passing through the
    > > hierarchy can be made easier. By defining a record type in a global
    > > package which contains elements for each constant required, we can
    > > have a flexible "handle" by which to pass all the parameters to
    > > every level with a single generic map association. Whenever a new
    > > parameter is needed, the record type is changed to add it, the value
    > > is set at the top (entity, instance, configuration, or tool) and
    > > only the lower level entity/architecture that needs it is modified
    > > to extract it from the record.

    > [snip]
    > > Comments?

    >
    > Just one clarification needed.
    >
    > Correct me if I'm wrong: I suppose you also declare a signal in the
    > package. The type of the signal is the record type. And with a
    > concurrent signal assignment in the toplevel architecture you assign
    > the toplevel generic to that signal. It is that signal that you use
    > (read) at the lower levels. The signal is made visable by a use
    > clause at those levels.
    >
    > > No matter which method is used (constants or generics), I strongly
    > > recommend subtyping them to constrain the values to practical
    > > limits. If a parameter must, say, be a integral power of two, then a
    > > concurrent assertion statement should verify that at the point of
    > > use.

    >
    > Couldn't agree more. Although I would use the exponent as generic and
    > do the exponentiation (2**generic) where I need it (via a constant so
    > it is only compted once).
    >
    > --
    > Paul.


    While generics are not locally static, at least they are static.
    Signals, even when driven from constants/generics, cannot drive range
    constraints, generate statements, etc.

    You are correct about the exponent example, but i've run into cases
    where it was not as simple as that, and I could not adequately
    constrain a generic to ensure compliance with the limitations of the
    design. You also bring up a good point about related parameters:
    whenever possible, they should be specified as one value, and the other
    values calculated from them (a good example might be a bitwidth and a
    corresponding numerical range, calculated via exponentiation).
    Whenever one cannot be calculated from the others, but must meet some
    relational requirement (i.e. a must be less than b) then an assertion
    at the point of use is a good thing to use to verify it. Some
    simulators will evaluate concurrent assertion statements with static
    expressions during elaboration, before simulation even starts.

    Andy
    Andy, Oct 9, 2006
    #7
  8. Andrew FPGA

    Andy Guest

    Here is an example of a package and top level entity/architecture that
    uses a record for the generic at the lower levels, but breaks it out at
    the top level to make it easier to deal with setting generic values by
    tool command line options.

    Andy

    library ieee;
    use ieee.std_logic_1164.all;

    package parameters is
    -- define parameter record structure
    type param_t is
    record
    ns_per_clk : positive; -- clock period in ns
    num_channels : positive; -- number of input channels
    channel_width : positive; -- width of each channel
    end record;

    -- (optional) define a set of default values for the parameters
    constant default_param : param_t := (
    ns_per_clk => 10,
    num_channels => 16,
    channel_width => 8
    );

    subtype slv is std_logic_vector; -- abbreviation

    end package parameters;

    library ieee;
    use ieee.std_logic_1164.all;
    use work.parameters.all;

    entity top is
    -- To maintain compatibility with compilers that do not
    -- allow cmd line specification of non-scalar generic values,
    -- we can separately define the individual generics here
    -- then combine them into a record in the top level architecture.

    generic ( -- individual scalar generics for tool compatibility
    ns_per_clk : positive := default_param.ns_per_clk;
    num_channels : positive := default_param.num_channels;
    channel_width : positive := default_param.channel_width
    );
    port (
    clk, we : in std_logic;
    input : in slv(channel_width - 1 downto 0);
    addr : in natural range 0 to num_channels - 1;
    output : out slv(channel_width - 1 downto 0)
    );

    end entity top;

    architecture rtl of top is
    -- define parameter record contents for lower level generic
    constant p : param_t := (
    ns_per_clk => ns_per_clk,
    num_channels => num_channels,
    channel_width => channel_width
    );

    begin
    u1: entity work.lower_level(rtl)
    generic map ( -- pass just one parameter record
    p => p
    )
    port map (
    clk => clk,
    we => we,
    addr => addr,
    input => input,
    output => output
    );
    end architecture rtl;



    Mike Treseler wrote:
    > Andy wrote:
    >
    > > Generics are not locally static, and must be passed down through the
    > > hierarchy if they are to be centrally managed. However, they can be
    > > managed within the abilities of vhdl, without resorting to file naming
    > > slight-of-hand, by instantiation, configuration, and tool command line
    > > options.

    >
    > Yes, for a related example, see seed_c below:
    >
    > generic (tb_char_g : natural := 8; -- generic length
    >
    > --...
    > constant msb : natural := tb_char_g -1;
    > -- generic
    >
    > subtype char_t is unsigned(msb downto 0);
    > -- generic type, usually 8 bits
    >
    > constant zero_c : char_t := (others => '0');
    > -- generic type, usually 8 bits
    >
    > constant seed_c : char_t := "100001" + zero_c;
    > -- follows wider generic widths
    >
    > > Whenever a new parameter is
    > > needed, the record type is changed to add it, the value is set at the
    > > top (entity, instance, configuration, or tool) and only the lower level
    > > entity/architecture that needs it is modified to extract it from the
    > > record.

    >
    > Very clever.
    > Thanks for the posting.
    >
    > > Comments?

    >
    > Could we trouble you for a simple example?
    >
    > -- Mike Treseler
    Andy, Oct 9, 2006
    #8
  9. Hi Andy,

    Good summary - thanks!

    "Andy" <> writes:
    > BTW, I almost always use a ns_per_clk : positive generic to pass clock
    > period info for timers, etc.


    One question:

    Do you find ns to be sufficiently precise? Or are you lucky int hat
    all your clocks come out as a round number of ns?

    > If a parameter must, say, be a integral power of two, then a concurrent
    > assertion statement should verify that at the point of use.
    >


    Absolutely!

    Cheers,
    Martin

    --

    TRW Conekt - Consultancy in Engineering, Knowledge and Technology
    http://www.conekt.net/electronics.html
    Martin Thompson, Oct 10, 2006
    #9
  10. Andrew FPGA

    KJ Guest

    "Andy" <> wrote in message
    news:...
    > I've found a very interesting hybrid approach to managing constant
    > design parameters, but let me summarize some pro's and con's of
    > constants vs generics.
    >
    > While there is nothing that can be done to address the non-locally
    > static problem of generics, managing their passing through the
    > hierarchy can be made easier.

    I guess I haven't found the managing of generic passing to be difficult...no
    different than a signal.

    > By defining a record type in a global
    > package which contains elements for each constant required, we can have
    > a flexible "handle" by which to pass all the parameters to every level
    > with a single generic map association. Whenever a new parameter is
    > needed, the record type is changed to add it, the value is set at the
    > top (entity, instance, configuration, or tool) and only the lower level
    > entity/architecture that needs it is modified to extract it from the
    > record.

    Perhaps we're seeing things a bit differently but when I pass my generics
    through the hierarchy, the list-o-generics is generally quite a bit smaller
    than the list-o-signals so having mapping for each of the generics is not
    that tedious.

    The other big problem is that the idea doesn't scale well. Within the
    individual entity/architecture that will actually use the generic you now
    have basically a global naming problem (i.e. entity foo uses G.some_integer
    to control something). But then sometime later you create a new entity H
    which needs some integer value so you think to use the 'some_integer' entry
    to pass that value down.....still later you want to use both G and H in some
    design and they are now both coded to use 'some_integer' but need them set
    differently. The only way around that problem is to have that record type
    continuously growing with each new parameter of each entity that you ever
    write so that they are all totally independent. This gets to be an ugly
    looking thing when...
    - You go to assign values and have to assign all sorts of constants that
    have nothing to do with today's design but they are in the record type
    because they are used in entities A, B, C, D...etc. that were written years
    ago.
    - The individual record type names will also grow ugly because you will need
    something like 'some_integer_for_entity_G' and 'some_integer_for_entity_H'
    and the actual naming of generics will depend on the generics for every
    other design that you've ever written up to that point.
    - Then you'll try to integrate that with code that somebody else wrote
    (using this same method) and have real ugliness because your record
    definition will be completely different than theirs. So now you'll either
    have to integrate their record type into yours and maintain the 'single'
    generic approach or break your approach and pass in two generics, one of
    'my_type' of one 'their_type'....which now makes all of those entities that
    use two generics off in their own little space of all of the IP that you've
    written.
    - There will be no common standard for this generic. Instead the record
    definition will be sort of a trail or history showing the various designs
    that engineer 'X' has ever written in their career.
    - As you get more sophisticated with the types of things you want to pass in
    as generics you'll bust through and want to pass custom record types and
    arrays and such (in case you're thinking that this is too esoteric, it's
    not, I do this) which will mean that you'll need to include those custom
    record types for the entire history of your career in every new design which
    you probably do not want to do either.
    - At some point the record type will get too unwieldy (becuase of the above
    mentioned scaling issues) and you'll say to heck with it and chop it at some
    point and create a second scaled down record type for 'simple'
    generics....and repeat the same basic cycle.

    Passing things that won't change from design to design (like the need for a
    'clock period' generic) won't typically have this problem but I've found
    this to be only a small fraction of the generics; most of them are specific
    to the entity.

    >
    > BTW, I almost always use a ns_per_clk : positive generic to pass clock
    > period info for timers, etc. Synopsis used to not be able to specify
    > non-integer generics from the command line. I don't know if they can
    > today. To get around such a problem with records, the top leve entity
    > can have all the separate integer generics declared, and then assemble
    > them into a record in the top level architecture, for passing down
    > through the hierarchy.

    Use of an integer like 'ns_per_clk' instead of simply using 'time' is
    usually a band-aid because some tool (translated: synthesis tool) doesn't
    support type 'time'. Synplify supports time types now because of a bug
    report I submitted a couple years back...and they should support it
    correctly soon because of yet another bug report I recently submitted.
    Quartus supports 'time' and a couple other tools I've tried do as well
    (forget exactly which ones I've tried it on, but I know I haven't tried it
    on ISE yet).

    In any case, use of integers is less descriptive than time. 'ns_per_clk'
    becomes a bit of an issue when (if?) you at some point in the future find
    yourself describing something near a GHz. Round off errors (i.e. using 7 or
    8 instead of 7.8) for the clock period becomes a problem. Depending on how
    that number ultimately gets used rounding down might not be appropriate in
    some cases, rounding up in others....don't have that issue with 'time'.
    Also the 'units' are more easily carried along and handled automatically.
    I'd much rather see 25.4 us than 25400 and have to mentally remember the
    units are 'ns_per_clk'....or did we switch to 'ps_per_clk' and the number
    should be 25400000 (let me check, did I get the right number of '0's?)
    >
    > No matter which method is used (constants or generics), I strongly
    > recommend subtyping them to constrain the values to practical limits.

    I would say limit them to ranges that you've at least somewhat tested.

    > If a parameter must, say, be a integral power of two, then a concurrent
    > assertion statement should verify that at the point of use.

    Yep, assertion check your generics so they don't get misused.

    KJ
    KJ, Oct 10, 2006
    #10
  11. Andrew FPGA

    Andy Guest

    KJ,

    Thanks for the comments, you raise some really good points...

    I've had FPGA designs with dozens of centralized parameters; assuming
    you want those managed from one place, there are two reasonable
    possibilities, a global package of constants, or generic records.

    With generics, the parameters must be passed through every level, from
    the top down to where they are needed. In a large, complex design,
    managing what goes where is a lot tougher than managing a record
    typedef, and passing everything everywhere. The record typedef becomes
    the conduit, and you can pull as many wires through it as you want
    (unlike a real conduit!), only having to worry about the endpoints, not
    all the interfaces along the way.

    BTW, I've used records for signal interfaces too, but they get uglier
    with in/out/inout modes. They're supposed to be working on that (mode
    definitions for multi-mode record ports). Since generics are always
    like "mode in", records work extremely well for generics.

    If naming collisions between record elements get to be a problem, you
    could break up the record into subrecords for different sets of related
    parameters, or even mimic the hierarchy of the design in the record
    itself. The latter may or may not work so well when the same parameter
    is used in different leaves of the hierarchy, since referencing it in
    one leaf requires knowledge of the location of the other leaf where it
    is set in the record.

    You can also define functions along with the record type that override
    a given element in the record, while passing the others intact, so you
    do not have to manually break out the record elements and assign them
    individually when you need to override an individual record element
    before passing it on down. This would be helpful if an architecture
    modifies a port width (muxing or demuxing it), or DCM's the clock
    before handing it to a lower level entity.

    Naming collisions between record elements and local objects do not
    exist, since the elements are always prefixed with the record whose
    type resolves the reference. You'll notice the top level individual
    generics in the example have the same names as the record elements, and
    that compiles ok.

    I don't really see any difference, WRT the history of a designer's
    designs, between a global package opf constants and using generics to
    centrally manage design parameters. You'd have to prune the package or
    the record to keep the parameters pared to those needed in the current
    design. Using a record simplifies the generic pruning (compared to
    separate generics), since it need only be done in one place (or two, if
    you break them out individually at the top level)

    It sounds like your argument is more specifically against centralized
    parameter management, preferring to manage the parameters at the point
    of use (at which point they cease being a parameter), or slightly above
    it. That's another approach that has both strengths and weaknesses. I
    like having a single 'parameter set' that controls the whole design,
    and multiple ways to control that (defaults, instance generic map,
    configurations, and tool options), but it does have its costs in
    maintenance, etc. Centralized management also is really nice when two
    distant entities need the same parameter. Managing them locally to each
    entity invites problems with keeping them in sync.

    Using a subtype of time for the clock period is a superior solution, so
    long as your toolset, including simulation, formal analysis, synthesis,
    etc. supports it universally. Some tools even support setting record
    type generics on the command line, but unless they also support named
    association (and not just a parenthesized list of values), that would
    get really ugly, and it would probably be better to break them out into
    individual generics at the top level if you intend to manage them
    through the tool. If instead you only want to manage them through the
    language (instance generic maps, configuration declarations, etc.) then
    there is no need to break them out at the top level.

    > I would say limit them [generic subtypes] to ranges that you've at least somewhat tested.


    Thanks, that's a better way to define "practical".

    Andy
    Andy, Oct 10, 2006
    #11
  12. Andrew FPGA

    Ben Jones Guest

    "KJ" <> wrote in message
    news:EMKWg.4918$...

    > The other big problem is that the idea doesn't scale well. Within the
    > individual entity/architecture that will actually use the generic you now
    > have basically a global naming problem (i.e. entity foo uses
    > G.some_integer to control something). But then sometime later you create
    > a new entity H which needs some integer value so you think to use the
    > 'some_integer' entry to pass that value down.....still later you want to
    > use both G and H in some design and they are now both coded to use
    > 'some_integer' but need them set differently. The only way around that
    > problem is to have that record type continuously growing with each new
    > parameter of each entity that you ever write so that they are all totally
    > independent. <snip>


    Sounds like a "slippery slope" argument to me. :) No-one said you had to
    have "just one" of these record types in your design...

    I find that grouping signals and generics into record types early on in the
    design phase is very useful. It massively reduces the amount of typing that
    is needed to connect some signals from one block to another, and
    simultaneously makes the code clearer because the reader doesn't have to sit
    and compare two port lists to see that every signal in a group is connected
    between A and B. And as previously pointed out, if you suddenly discover
    that you need an extra signal or an extra generic in one of these bundles -
    like I did this morning, in fact - you only need to add it in the definition
    and the points of use; no need to go hunting through dozens of files adding
    signals to entity declarations and port maps.

    With generics, you definitely want to do this on a project-by-project basis.
    I didn't experience the "explosion of fields in one monolithic record type"
    problem; I think that would be a bit of an extreme situation. Rather, I tend
    to have some high-level, design-specific information - such as which
    features are supported, what latencies and relative latencies my
    sub-components should have, and various derivative information - and keep
    the local/ephemeral stuff local.

    This approach also allows you to do some concentrated parameter checking by
    writing a function to validate your record of generics (e.g. checking for
    contradictory parameters). This, in addition to as many local assertions
    etc. as necessary, seems be quite a robust way to manage your design
    configuration.

    Cheers,

    -Ben-
    Ben Jones, Oct 10, 2006
    #12
  13. Andrew FPGA

    KJ Guest

    Andy wrote:
    > KJ,
    >
    > Thanks for the comments, you raise some really good points...
    >
    > I've had FPGA designs with dozens of centralized parameters; assuming
    > you want those managed from one place, there are two reasonable
    > possibilities, a global package of constants, or generic records.

    I prefer to put the constants in the top level of the design itself.
    If there are multiple designs that need to access the same constant
    then it would go into a package. By 'top level of the design' I mean
    that if for example, I have three FPGAs and one CPLD on a board then
    each of those parts will have some 'top level' source file and that's
    the place I would put all but the shared constants.

    I realize I could pull those constants out and make them generics as
    well and bring them up higher but then you can run into the problem of
    you're simulating one way for building actual parts another. By
    stopping the generics at the top level of a physical design and making
    them constants at that level, there is no chance of that happening. In
    simulating real board designs with multiple parts I find that one less
    headache is a good thing but others might like to bring those constants
    out to be tweaked by the simulation testbench model itself and then
    manually manage that synthesis builds use the correct parameter values.

    > With generics, the parameters must be passed through every level, from
    > the top down to where they are needed. In a large, complex design,
    > managing what goes where is a lot tougher than managing a record
    > typedef, and passing everything everywhere. The record typedef becomes
    > the conduit, and you can pull as many wires through it as you want
    > (unlike a real conduit!), only having to worry about the endpoints, not
    > all the interfaces along the way.

    I agree it is easier to manage things through the single generic record
    type IF the entity is in flux and subject to change. I just haven't
    hit the "threshold of pain" yet where this management hurts. Now maybe
    the only reason for that is because of editor macros and the way I go
    about instantiating an entity the first time. Plopping down an entity
    to use it somewhere generally takes me mere moments regardless of how
    many signals and generics there are.

    Now if the entity itself is in flux and the signals or generics are
    frequently changing then the record approach will pay for itself in
    time....but so would nailing down the entity in the first place.

    >
    > BTW, I've used records for signal interfaces too, but they get uglier
    > with in/out/inout modes. They're supposed to be working on that (mode
    > definitions for multi-mode record ports). Since generics are always
    > like "mode in", records work extremely well for generics.

    I tried records for signal interfaces also and didn't like the way
    Modelsim handled it in the 'Dataflow' window which I use while
    debugging. I came to the conclusion that while it did sort of look
    tidy to have all of the 'gazintas' in a single record, (and gazoutas
    and bi-directs) in practice I didn't like to use it.

    >
    > If naming collisions between record elements get to be a problem, you
    > could break up the record into subrecords for different sets of related
    > parameters, or even mimic the hierarchy of the design in the record
    > itself. The latter may or may not work so well when the same parameter
    > is used in different leaves of the hierarchy, since referencing it in
    > one leaf requires knowledge of the location of the other leaf where it
    > is set in the record.

    Getting messy ;)

    >
    > You can also define functions along with the record type that override
    > a given element in the record, while passing the others intact, so you
    > do not have to manually break out the record elements and assign them
    > individually when you need to override an individual record element
    > before passing it on down. This would be helpful if an architecture
    > modifies a port width (muxing or demuxing it), or DCM's the clock
    > before handing it to a lower level entity.

    Functions are great that way.

    > I don't really see any difference, WRT the history of a designer's
    > designs, between a global package opf constants and using generics to
    > centrally manage design parameters.

    I don't either. I'll just point out that the "edit all of the design
    parameters in a single file" can also be accomplished by simply putting
    them as constants in whatever the 'top level' is.

    We already agree that there are advantages to the record approach.
    Where I was going with the "history of a designer's designs" was from
    the standpoint of design reuse. In order to reuse the code without
    modification you would need to not change the name of that record type.
    This would lead one to choose a name for that record "KJ_Generics" and
    always use that. That way any code that I write could safely get at
    any record elements. Now you've done the same thing but I'm guessing
    that yours might be called "Andys_Generics" or something...but
    certainly not "KJ_Generics". Integrating our code will cause a bit of
    headaches on those generics.

    Using a record name that is somehow associated with the project
    "ProjectX_Generics" doesn't solve the problem when you try to reuse
    code on "Project Y".

    If you don't reuse code much then this is not an issue....but since you
    probably do I think it will.

    > You'd have to prune the package or
    > the record to keep the parameters pared to those needed in the current
    > design. Using a record simplifies the generic pruning (compared to
    > separate generics), since it need only be done in one place (or two, if
    > you break them out individually at the top level)

    And that pruning will be a reason to make sure you don't do the design
    specific sort of path name thing that I think you were alluding to
    either. You wouldn't want any parameter to be down a path since it
    will probably be down a different path when reused in a different
    design.

    >
    > It sounds like your argument is more specifically against centralized
    > parameter management, preferring to manage the parameters at the point
    > of use (at which point they cease being a parameter), or slightly above
    > it.

    No I manage it at the top level of each physical design as I mentioned
    earlier which is just as centralized, definitely not point of use.
    Must've been confusing in my wording.

    > That's another approach that has both strengths and weaknesses. I
    > like having a single 'parameter set' that controls the whole design,
    > and multiple ways to control that (defaults, instance generic map,
    > configurations, and tool options), but it does have its costs in
    > maintenance, etc. Centralized management also is really nice when two
    > distant entities need the same parameter. Managing them locally to each
    > entity invites problems with keeping them in sync.

    I agree but like I said I don't like to ever be caught in the situation
    when there is a problem on a real board that needs debugging and I'm
    simulating something that is different because of a difference in
    parameter settings. Putting the constants at the top level of each
    physical design (but putting constants that are shared between designs
    into a package) is the best way I've found to avoid getting into that
    situation.

    > Using a subtype of time for the clock period is a superior solution, so
    > long as your toolset, including simulation, formal analysis, synthesis,
    > etc. supports it universally.

    And complain to the tool vendor when they don't, that's the best way to
    improve the tool (although not guaranteed to work). Synplify responded
    on my beef with 'time'. It doesn't get you past the immediate problem
    if the tool chokes but like I said that's when you can band-aid it with
    a type that the tool is happy with.

    > Some tools even support setting record
    > type generics on the command line, but unless they also support named
    > association (and not just a parenthesized list of values), that would
    > get really ugly, and it would probably be better to break them out into
    > individual generics at the top level if you intend to manage them
    > through the tool. If instead you only want to manage them through the
    > language (instance generic maps, configuration declarations, etc.) then
    > there is no need to break them out at the top level.

    Another good reason for leaving them as constants where I do...less
    tool specific issues.

    > > I would say limit them [generic subtypes] to ranges that you've at least somewhat tested.

    >
    > Thanks, that's a better way to define "practical".
    >

    Good discussion. The idea of a single generic as a record type is
    certainly a 'neat and tidy' solution that has a lot of merit. Whether
    people find it productive or not I think would depend on how fluid
    those entity definitions are and the design reuse perspective....and
    both of those will probably a function of the particular engineer and
    the company they work for, etc.

    KJ
    KJ, Oct 10, 2006
    #13
  14. Andrew FPGA

    KJ Guest

    Ben Jones wrote:
    > "KJ" <> wrote in message
    > news:EMKWg.4918$...
    >
    > > The other big problem is that the idea doesn't scale well. Within the
    > > individual entity/architecture that will actually use the generic you now
    > > have basically a global naming problem (i.e. entity foo uses
    > > G.some_integer to control something). But then sometime later you create
    > > a new entity H which needs some integer value so you think to use the
    > > 'some_integer' entry to pass that value down.....still later you want to
    > > use both G and H in some design and they are now both coded to use
    > > 'some_integer' but need them set differently. The only way around that
    > > problem is to have that record type continuously growing with each new
    > > parameter of each entity that you ever write so that they are all totally
    > > independent. <snip>

    >
    > Sounds like a "slippery slope" argument to me. :) No-one said you had to
    > have "just one" of these record types in your design...

    That was implicit I thought...

    >
    > I find that grouping signals and generics into record types early on in the
    > design phase is very useful. It massively reduces the amount of typing that
    > is needed to connect some signals from one block to another, and
    > simultaneously makes the code clearer because the reader doesn't have to sit
    > and compare two port lists to see that every signal in a group is connected
    > between A and B.

    I use copy/paste and an editor macro to weed out these problems....it
    works when you first instantiate the component so if the entity does
    not need to change I'm fine...but...read on...
    > And as previously pointed out, if you suddenly discover
    > that you need an extra signal or an extra generic in one of these bundles -
    > like I did this morning, in fact - you only need to add it in the definition
    > and the points of use; no need to go hunting through dozens of files adding
    > signals to entity declarations and port maps.

    And I agree, if the entity definition is in flux and signals get
    added/removed then having things collected into a record definitely
    simplifies the maintenance. If the entity is solid then there is no
    benefit if you instantiate the entity one time; if it's more than that
    (and that instantiatin is not in a generate statement) then again the
    record approach would result in less typing.

    Although this is somewhat off the beaten path of the topic of this
    thread, what I've found is when you standardize on a logical interface
    for all entities that the entity definition itself firms up quickly and
    you don't have the situation as often where you need to bring in a
    signal. The standardization doesn't cause much/any actual logic
    resource overhead. I think this basic approach be better as a general
    principle but I'm not going that far, just my hunch. What I can say is
    that since doing this I've been doing very little (if any) futzing with
    the entity to fix any problem, it's always in the architecture.
    >
    > With generics, you definitely want to do this on a project-by-project basis.
    > I didn't experience the "explosion of fields in one monolithic record type"
    > problem; I think that would be a bit of an extreme situation. Rather, I tend
    > to have some high-level, design-specific information - such as which
    > features are supported, what latencies and relative latencies my
    > sub-components should have, and various derivative information - and keep
    > the local/ephemeral stuff local.

    Like I mentioned in my post back to Andy, you may have to be careful
    when trying to reuse designs between projects. Depending on your
    situation though this may not apply even when you do reuse code, just
    something to keep in mind.

    >
    > This approach also allows you to do some concentrated parameter checking by
    > writing a function to validate your record of generics (e.g. checking for
    > contradictory parameters). This, in addition to as many local assertions
    > etc. as necessary, seems be quite a robust way to manage your design
    > configuration.

    Right, and I'll concentrate my parameter checking in the architecture.
    Either way I think is roughly equivalent amount of work just different
    ways of doing things.

    KJ
    KJ, Oct 10, 2006
    #14
  15. Andrew FPGA

    Jim Lewis Guest

    Re: Generics vs Constants - what criteria do you use to choose betweenthese?

    Andy,
    > BTW, I've used records for signal interfaces too, but they get uglier
    > with in/out/inout modes. They're supposed to be working on that (mode
    > definitions for multi-mode record ports). Since generics are always
    > like "mode in", records work extremely well for generics.


    I am one of the people in the standards group who is looking at
    this. Can you send me some examples (directly) of how you are
    currently using this and perhaps some of the things you would
    like to be able to do.

    Standards groups are becomming more and more user driven.
    As a result, we need more user participation and more user
    examples/feature requests to support implementing a feature.

    Do you want to use it for RTL? If so how? Do you want to
    use it for testbenches? If so how?

    Thanks,
    Jim
    --
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Jim Lewis
    Director of Training mailto:
    SynthWorks Design Inc. http://www.SynthWorks.com
    1-503-590-4787

    Expert VHDL Training for Hardware Design and Verification
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Jim Lewis, Oct 10, 2006
    #15
  16. Andrew FPGA

    Andy Guest

    KJ,

    OK, I think I had the wrong impression of how you were managing
    parameters. So, if I understand you correctly, you define constants at
    the top (fpga) level architecture, and then pass those down as
    individual generics through the hierarchy to their individual point(s)
    of use? And you generally only use a handful of those top level
    constants/lower level generics.

    If so, there is very little coding difference between a constant
    declaration and a generic declaration with a default value at the top
    level. And the overhead in handling the relatively few generics is not
    worth the extra effort of creating the record. That certainly works, so
    long as the number of parameters being managaed from the top is
    relatively small, and/or is fairly well set in concrete. Neither of
    those tends to be true in my work...

    On the subject of design reuse, say I'm reusing a module in an upgrade
    to an existing FPGA. I now have to patch the new generics for that
    module all the way through the hierarchy up to the top (granted,
    depending on the interfaces, the ports may have to be plumbed up to the
    top too). If that module used a package xy for its generic record
    typedef jk, then all I'd have to do is create/modify an xy package
    where I declared subtype jk is ab, where ab is my main design's generic
    typedef from my main package. Then add the elements the module needs to
    my main typedef ab. Hook the module up to my existing generic, and I'm
    done. There's no need to have a common name for the package or the
    generic record type, just the name of the element.

    If I run into a naming collision on the element name, I could also
    handle that with a type conversion function on the instance generic map
    of the lower level module. Say the module needs an element called 'a',
    but there's already an 'a' defined in the ab record for something else.
    Put the data into the ab record under a different name, then at the
    module's instance generic map, use a type conversion function to rename
    the new element name back to 'a'. That type conversion could even be
    used in a configuration.

    There are many reasons to have different configurations for simulation
    and build, but you're right, at some point you need to simulate the
    as-built configuration. Having named vhdl configurations for these
    helps in keeping track of what you are simulating or building. Keeping
    track of them with differently named top level architectures works too,
    but there is a lot of extra baggage that has to be maintained (like the
    interconnects and insances of all the lower level modules!) in each of
    those. I use simulation-only configurations to omit unused parts of the
    circuit when I'm testing something else, so it greatly speeds up the
    simulation. I may also test the design with a slower clock in order to
    simulate fewer clock cycles for a given simulated time interval (for
    rtl only). These kinds of simulations run much faster to rat out most
    of the bugs, then the final, full-up simulation makes sure the bugs
    stay gone. The faster the simulations run, the more corner cases I can
    verify, and the more bugs I get out. The slower, as-built simulation is
    run relatively few times, since most of the bugs are found and fixed
    before that. The same process works for gate level vs rtl level
    simulations.

    BTW, in my designs, the as-built configuration (unless there are
    multiple as-built configurations) is always represented by the default
    generic assignments at the top level entity (or if they are mapped to a
    named constant, then the default values are defined in the top level
    package. The bottom line is, the as-built configuration always works
    with no generic map, no tool overrides, and no vhdl configurations.

    You're right, this is a good discussion.

    Andy


    KJ wrote:
    > Andy wrote:
    > > KJ,
    > >
    > > Thanks for the comments, you raise some really good points...
    > >
    > > I've had FPGA designs with dozens of centralized parameters; assuming
    > > you want those managed from one place, there are two reasonable
    > > possibilities, a global package of constants, or generic records.

    > I prefer to put the constants in the top level of the design itself.
    > If there are multiple designs that need to access the same constant
    > then it would go into a package. By 'top level of the design' I mean
    > that if for example, I have three FPGAs and one CPLD on a board then
    > each of those parts will have some 'top level' source file and that's
    > the place I would put all but the shared constants.
    >
    > I realize I could pull those constants out and make them generics as
    > well and bring them up higher but then you can run into the problem of
    > you're simulating one way for building actual parts another. By
    > stopping the generics at the top level of a physical design and making
    > them constants at that level, there is no chance of that happening. In
    > simulating real board designs with multiple parts I find that one less
    > headache is a good thing but others might like to bring those constants
    > out to be tweaked by the simulation testbench model itself and then
    > manually manage that synthesis builds use the correct parameter values.
    >
    > > With generics, the parameters must be passed through every level, from
    > > the top down to where they are needed. In a large, complex design,
    > > managing what goes where is a lot tougher than managing a record
    > > typedef, and passing everything everywhere. The record typedef becomes
    > > the conduit, and you can pull as many wires through it as you want
    > > (unlike a real conduit!), only having to worry about the endpoints, not
    > > all the interfaces along the way.

    > I agree it is easier to manage things through the single generic record
    > type IF the entity is in flux and subject to change. I just haven't
    > hit the "threshold of pain" yet where this management hurts. Now maybe
    > the only reason for that is because of editor macros and the way I go
    > about instantiating an entity the first time. Plopping down an entity
    > to use it somewhere generally takes me mere moments regardless of how
    > many signals and generics there are.
    >
    > Now if the entity itself is in flux and the signals or generics are
    > frequently changing then the record approach will pay for itself in
    > time....but so would nailing down the entity in the first place.
    >
    > >
    > > BTW, I've used records for signal interfaces too, but they get uglier
    > > with in/out/inout modes. They're supposed to be working on that (mode
    > > definitions for multi-mode record ports). Since generics are always
    > > like "mode in", records work extremely well for generics.

    > I tried records for signal interfaces also and didn't like the way
    > Modelsim handled it in the 'Dataflow' window which I use while
    > debugging. I came to the conclusion that while it did sort of look
    > tidy to have all of the 'gazintas' in a single record, (and gazoutas
    > and bi-directs) in practice I didn't like to use it.
    >
    > >
    > > If naming collisions between record elements get to be a problem, you
    > > could break up the record into subrecords for different sets of related
    > > parameters, or even mimic the hierarchy of the design in the record
    > > itself. The latter may or may not work so well when the same parameter
    > > is used in different leaves of the hierarchy, since referencing it in
    > > one leaf requires knowledge of the location of the other leaf where it
    > > is set in the record.

    > Getting messy ;)
    >
    > >
    > > You can also define functions along with the record type that override
    > > a given element in the record, while passing the others intact, so you
    > > do not have to manually break out the record elements and assign them
    > > individually when you need to override an individual record element
    > > before passing it on down. This would be helpful if an architecture
    > > modifies a port width (muxing or demuxing it), or DCM's the clock
    > > before handing it to a lower level entity.

    > Functions are great that way.
    >
    > > I don't really see any difference, WRT the history of a designer's
    > > designs, between a global package opf constants and using generics to
    > > centrally manage design parameters.

    > I don't either. I'll just point out that the "edit all of the design
    > parameters in a single file" can also be accomplished by simply putting
    > them as constants in whatever the 'top level' is.
    >
    > We already agree that there are advantages to the record approach.
    > Where I was going with the "history of a designer's designs" was from
    > the standpoint of design reuse. In order to reuse the code without
    > modification you would need to not change the name of that record type.
    > This would lead one to choose a name for that record "KJ_Generics" and
    > always use that. That way any code that I write could safely get at
    > any record elements. Now you've done the same thing but I'm guessing
    > that yours might be called "Andys_Generics" or something...but
    > certainly not "KJ_Generics". Integrating our code will cause a bit of
    > headaches on those generics.
    >
    > Using a record name that is somehow associated with the project
    > "ProjectX_Generics" doesn't solve the problem when you try to reuse
    > code on "Project Y".
    >
    > If you don't reuse code much then this is not an issue....but since you
    > probably do I think it will.
    >
    > > You'd have to prune the package or
    > > the record to keep the parameters pared to those needed in the current
    > > design. Using a record simplifies the generic pruning (compared to
    > > separate generics), since it need only be done in one place (or two, if
    > > you break them out individually at the top level)

    > And that pruning will be a reason to make sure you don't do the design
    > specific sort of path name thing that I think you were alluding to
    > either. You wouldn't want any parameter to be down a path since it
    > will probably be down a different path when reused in a different
    > design.
    >
    > >
    > > It sounds like your argument is more specifically against centralized
    > > parameter management, preferring to manage the parameters at the point
    > > of use (at which point they cease being a parameter), or slightly above
    > > it.

    > No I manage it at the top level of each physical design as I mentioned
    > earlier which is just as centralized, definitely not point of use.
    > Must've been confusing in my wording.
    >
    > > That's another approach that has both strengths and weaknesses. I
    > > like having a single 'parameter set' that controls the whole design,
    > > and multiple ways to control that (defaults, instance generic map,
    > > configurations, and tool options), but it does have its costs in
    > > maintenance, etc. Centralized management also is really nice when two
    > > distant entities need the same parameter. Managing them locally to each
    > > entity invites problems with keeping them in sync.

    > I agree but like I said I don't like to ever be caught in the situation
    > when there is a problem on a real board that needs debugging and I'm
    > simulating something that is different because of a difference in
    > parameter settings. Putting the constants at the top level of each
    > physical design (but putting constants that are shared between designs
    > into a package) is the best way I've found to avoid getting into that
    > situation.
    >
    > > Using a subtype of time for the clock period is a superior solution, so
    > > long as your toolset, including simulation, formal analysis, synthesis,
    > > etc. supports it universally.

    > And complain to the tool vendor when they don't, that's the best way to
    > improve the tool (although not guaranteed to work). Synplify responded
    > on my beef with 'time'. It doesn't get you past the immediate problem
    > if the tool chokes but like I said that's when you can band-aid it with
    > a type that the tool is happy with.
    >
    > > Some tools even support setting record
    > > type generics on the command line, but unless they also support named
    > > association (and not just a parenthesized list of values), that would
    > > get really ugly, and it would probably be better to break them out into
    > > individual generics at the top level if you intend to manage them
    > > through the tool. If instead you only want to manage them through the
    > > language (instance generic maps, configuration declarations, etc.) then
    > > there is no need to break them out at the top level.

    > Another good reason for leaving them as constants where I do...less
    > tool specific issues.
    >
    > > > I would say limit them [generic subtypes] to ranges that you've at least somewhat tested.

    > >
    > > Thanks, that's a better way to define "practical".
    > >

    > Good discussion. The idea of a single generic as a record type is
    > certainly a 'neat and tidy' solution that has a lot of merit. Whether
    > people find it productive or not I think would depend on how fluid
    > those entity definitions are and the design reuse perspective....and
    > both of those will probably a function of the particular engineer and
    > the company they work for, etc.
    >
    > KJ
    Andy, Oct 10, 2006
    #16
  17. Andrew FPGA

    Andrew FPGA Guest

    Andy wrote:
    > I've found a very interesting hybrid approach to managing constant
    > design parameters, but let me summarize some pro's and con's of
    > constants vs generics.
    >
    > Comments?


    A single record generic is an interesting idea but the main issue I
    have with it is that it makes it harder to look at an entity and see
    straight away what has been paramatised for this entity. With a
    complete generic parameter list at the top of the entity its
    immediately obvious what aspects of the entity can be configured.

    I'm also worried about global namespace issue, its sort of like the
    reverse of encapsulation, all the parameters are spread to all
    entities/modules.

    Generics vs constants:
    I'm starting to form the opinion that most all paramaters that
    statically configure an entity should be in the generic list (or the
    port list in the case of Mike Treselers method). I can only think of a
    few exceptions:
    1) static configuration that affects almost all entities/modules across
    the project and that must take on the same value for all
    entities/modules. Even the clks_per_tic doesn't meet that requirement,
    although its a design goal to minimise the number of clks, its hardly
    ever 1.
    2) static configuration that affects a group of entities that can be
    put into a package that only that group of entities include. E.g.
    parameters for an optical link, like frame length, frame sync word etc
    where the optical link is implemented with several entities(say a
    receive framer, transmit framer etc).

    PS: I quite like Mike Treseler's method of using just normal port
    signals instead of generics. One advantage I can see if in the future
    you want to dynamically control the behaviour, just wire the port
    signal up to a cpu register bit, no change to the entity required. If
    you want it static just hold the control constant and synthesis
    optimises the control logic away.
    Andrew FPGA, Oct 10, 2006
    #17
  18. Andy wrote:

    > While generics are not locally static, at least they are static.
    > Signals, even when driven from constants/generics, cannot drive
    > range constraints, generate statements, etc.


    You're right. I suppose I got carried away a bit. Still, you can use a
    global signal in that way to convey some sorts of generics. I have
    done that at some occasion. Don't ask me whether it was
    synthesizable, it was behavioral code.

    > You are correct about the exponent example, but i've run into cases
    > where it was not as simple as that, and I could not adequately
    > constrain a generic to ensure compliance with the limitations of the
    > design. You also bring up a good point about related parameters:
    > whenever possible, they should be specified as one value, and the
    > other values calculated from them (a good example might be a
    > bitwidth and a corresponding numerical range, calculated via
    > exponentiation). Whenever one cannot be calculated from the others,
    > but must meet some relational requirement (i.e. a must be less than
    > b) then an assertion at the point of use is a good thing to use to
    > verify it. Some simulators will evaluate concurrent assertion
    > statements with static expressions during elaboration, before
    > simulation even starts.


    That's neat. And it follows a healthy principle: crash early.

    --
    Paul.
    Paul Uiterlinden, Oct 10, 2006
    #18
  19. Andrew FPGA

    Andy Guest

    Jim,

    I just want to be able to declare a record type, and then be able to
    declare one or more named modes for that type that indicate the
    individual modes on each element of the record for use in a port
    declaration. Note that for a record of records, you would also have a
    "mode of modes".

    For example, say I wanted to define a processor bus, and hook it up
    between a cpu and a peripheral. Both cpu and periph attach to the same
    signal (of type bus) but the cpu and peripheral drive/read different
    signals within that bus.

    Here is an idea of what I would like to be able to do, both for
    synthesis and testbenches :

    library ieee;
    use ieee.std_logic_1164.all;

    package bus_types is

    -- abbreviations
    subtype slv is std_logic_vector;
    subtype sl is std_logic;

    -- typedefs
    type bus_t is
    record
    addr : slv(0 to 35);
    as_n : sl;
    aack_n: sl;
    data : slv(0 to 63);
    ds_n : sl;
    dack_n: sl;
    ts : slv(0 to 2);
    tt : slv(0 to 3);
    end record bus_t;

    -- mode defs
    mode master of bus_t is -- new keyword "mode"???
    addr : out; -- only the name of the element need be repeated, not
    its type
    as_n : out; -- so changes in element types do not ripple to mode
    definitions
    aack_n : in;
    data : inout;
    ds_n : out;
    dack_n: in;
    ts : out;
    tt : out;
    end mode master;

    mode slave of bus_t is
    addr : in;
    as_n : in;
    aack_n : out;
    data : inout;
    ds_n : in;
    dack_n : out;
    ts : in;
    tt : in;
    end mode slave;

    end package bus_types;

    use work.bus_types.all;
    entity periph is
    port (pbus: slave bus_t); -- compiler selects & verifies mode slave
    exists for type bus_t
    end entity periph;

    use work.bus_types.all;
    entity cpu is
    port (pbus: master bus_t);
    end entity cpu;

    Then in some architecture, I could:

    architecture some of thing is

    signal mybus: bus_t;

    begin

    u1: entity work.cpu(rtl)
    port map (pbus => mybus);

    u2: entity work.periph(rtl)
    port map (pbus => mybus);

    end architecture rtl;

    In more complex examples, this could be used to quickly and easily
    plumb complex ports up/down through multiple levels of the hierarchy,
    in a "virtual" way such that the type and mode definitions can be
    changed, but the entities/architectures along the way remain unchanged.
    Think of a record/mode combination as a handle by which to abstract
    the interface.

    I could also use it in procedure calls in a testbench, such as write(),
    read(), or respond();

    Andy


    Jim Lewis wrote:
    > Andy,
    > > BTW, I've used records for signal interfaces too, but they get uglier
    > > with in/out/inout modes. They're supposed to be working on that (mode
    > > definitions for multi-mode record ports). Since generics are always
    > > like "mode in", records work extremely well for generics.

    >
    > I am one of the people in the standards group who is looking at
    > this. Can you send me some examples (directly) of how you are
    > currently using this and perhaps some of the things you would
    > like to be able to do.
    >
    > Standards groups are becomming more and more user driven.
    > As a result, we need more user participation and more user
    > examples/feature requests to support implementing a feature.
    >
    > Do you want to use it for RTL? If so how? Do you want to
    > use it for testbenches? If so how?
    >
    > Thanks,
    > Jim
    > --
    > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    > Jim Lewis
    > Director of Training mailto:
    > SynthWorks Design Inc. http://www.SynthWorks.com
    > 1-503-590-4787
    >
    > Expert VHDL Training for Hardware Design and Verification
    > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Andy, Oct 10, 2006
    #19
  20. Andrew FPGA

    Jim Lewis Guest

    Re: Generics vs Constants - what criteria do you use to choose betweenthese?

    Andy,
    That is about what I have gravitated toward.
    Since SystemVerilog has a similar capability with interfaces
    it confuses the issue some (as SV interfaces do much more).

    Should the record and mode be OO extensible?

    Cheers,
    Jim

    > Jim,
    >
    > I just want to be able to declare a record type, and then be able to
    > declare one or more named modes for that type that indicate the
    > individual modes on each element of the record for use in a port
    > declaration. Note that for a record of records, you would also have a
    > "mode of modes".
    >
    > For example, say I wanted to define a processor bus, and hook it up
    > between a cpu and a peripheral. Both cpu and periph attach to the same
    > signal (of type bus) but the cpu and peripheral drive/read different
    > signals within that bus.
    >
    > Here is an idea of what I would like to be able to do, both for
    > synthesis and testbenches :
    >
    > library ieee;
    > use ieee.std_logic_1164.all;
    >
    > package bus_types is
    >
    > -- abbreviations
    > subtype slv is std_logic_vector;
    > subtype sl is std_logic;
    >
    > -- typedefs
    > type bus_t is
    > record
    > addr : slv(0 to 35);
    > as_n : sl;
    > aack_n: sl;
    > data : slv(0 to 63);
    > ds_n : sl;
    > dack_n: sl;
    > ts : slv(0 to 2);
    > tt : slv(0 to 3);
    > end record bus_t;
    >
    > -- mode defs
    > mode master of bus_t is -- new keyword "mode"???
    > addr : out; -- only the name of the element need be repeated, not
    > its type
    > as_n : out; -- so changes in element types do not ripple to mode
    > definitions
    > aack_n : in;
    > data : inout;
    > ds_n : out;
    > dack_n: in;
    > ts : out;
    > tt : out;
    > end mode master;
    >
    > mode slave of bus_t is
    > addr : in;
    > as_n : in;
    > aack_n : out;
    > data : inout;
    > ds_n : in;
    > dack_n : out;
    > ts : in;
    > tt : in;
    > end mode slave;
    >
    > end package bus_types;
    >
    > use work.bus_types.all;
    > entity periph is
    > port (pbus: slave bus_t); -- compiler selects & verifies mode slave
    > exists for type bus_t
    > end entity periph;
    >
    > use work.bus_types.all;
    > entity cpu is
    > port (pbus: master bus_t);
    > end entity cpu;
    >
    > Then in some architecture, I could:
    >
    > architecture some of thing is
    >
    > signal mybus: bus_t;
    >
    > begin
    >
    > u1: entity work.cpu(rtl)
    > port map (pbus => mybus);
    >
    > u2: entity work.periph(rtl)
    > port map (pbus => mybus);
    >
    > end architecture rtl;
    >
    > In more complex examples, this could be used to quickly and easily
    > plumb complex ports up/down through multiple levels of the hierarchy,
    > in a "virtual" way such that the type and mode definitions can be
    > changed, but the entities/architectures along the way remain unchanged.
    > Think of a record/mode combination as a handle by which to abstract
    > the interface.
    >
    > I could also use it in procedure calls in a testbench, such as write(),
    > read(), or respond();
    >
    > Andy
    >
    >
    > Jim Lewis wrote:
    >
    >>Andy,
    >>
    >>>BTW, I've used records for signal interfaces too, but they get uglier
    >>>with in/out/inout modes. They're supposed to be working on that (mode
    >>>definitions for multi-mode record ports). Since generics are always
    >>>like "mode in", records work extremely well for generics.

    >>
    >>I am one of the people in the standards group who is looking at
    >>this. Can you send me some examples (directly) of how you are
    >>currently using this and perhaps some of the things you would
    >>like to be able to do.
    >>
    >>Standards groups are becomming more and more user driven.
    >>As a result, we need more user participation and more user
    >>examples/feature requests to support implementing a feature.
    >>
    >>Do you want to use it for RTL? If so how? Do you want to
    >>use it for testbenches? If so how?
    >>
    >>Thanks,
    >>Jim
    >>--
    >>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    >>Jim Lewis
    >>Director of Training mailto:
    >>SynthWorks Design Inc. http://www.SynthWorks.com
    >>1-503-590-4787
    >>
    >>Expert VHDL Training for Hardware Design and Verification
    >>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    >
    >



    --
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Jim Lewis
    Director of Training mailto:
    SynthWorks Design Inc. http://www.SynthWorks.com
    1-503-590-4787

    Expert VHDL Training for Hardware Design and Verification
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Jim Lewis, Oct 11, 2006
    #20
    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. RC
    Replies:
    5
    Views:
    341
    Chris Smith
    Aug 31, 2006
  2. arnuld
    Replies:
    33
    Views:
    1,177
  3. chewie54
    Replies:
    17
    Views:
    1,170
    Kryvor
    Nov 8, 2007
  4. Deep_Feelings
    Replies:
    12
    Views:
    490
    Paul Moore
    Jul 15, 2009
  5. Lloyd Zusman
    Replies:
    5
    Views:
    150
    Joel VanderWerf
    Feb 20, 2005
Loading...

Share This Page