enum as array index

Discussion in 'VHDL' started by Shannon, Jun 26, 2009.

  1. Shannon

    Shannon Guest

    I think this is how I have to do it. Am I making it too complex?
    Will it synthesize?


    type flag_type is (this, that, other);
    type flag_array_type is array (flag_type range <>) of std_logic;
    signal flag : flag_array_type(other downto this);

    ....
    --set the flag
    flag(that) <= '1';

    yes?

    Shannon
     
    Shannon, Jun 26, 2009
    #1
    1. Advertising

  2. Shannon wrote:

    > type flag_type is (this, that, other);
    > type flag_array_type is array (flag_type range <>) of std_logic;
    > signal flag : flag_array_type(other downto this);


    I use the type enum directly as the array index:

    type quality_t is (too_big, too_small, just_right);

    type stats_t is array (quality_t) of natural;

    constant stats_c : stats_t :=
    (too_small => 2, too_big => 1, just_right => 5);

    Works fine for synthesis.

    -- Mike Treseler
     
    Mike Treseler, Jun 26, 2009
    #2
    1. Advertising

  3. Shannon

    Shannon Guest

    On Jun 26, 11:23 am, Mike Treseler <> wrote:
    > Shannon wrote:
    > > type flag_type is (this, that, other);
    > > type flag_array_type is array (flag_type range <>) of std_logic;
    > > signal flag : flag_array_type(other downto this);

    >
    > I use the type enum directly as the array index:
    >
    > type quality_t is (too_big, too_small, just_right);
    >
    > type stats_t is array (quality_t) of natural;
    >
    > constant stats_c : stats_t :=
    > (too_small => 2, too_big => 1, just_right => 5);
    >
    > Works fine for synthesis.
    >
    >     -- Mike Treseler


    I was specific about the ordering since I am going to use the flag
    array to update a vector where the specific location of each bit is
    important (and fixed). Something like:

    Loop
    reg_status(i) <= reg_status(i) or flag(i);
    end loop

    This flag array is a list of fault bits.

    I like the looks of:

    flag(over_current) <= '1';
    ....
    flag(under_volt) <= '1';
    etc.
    Then the processor can read the reg_status word and can mask bits to
    look for certain faults. So the plan was to enum in order the fault
    flags.

    Shannon
     
    Shannon, Jun 26, 2009
    #3
  4. Shannon

    Shannon Guest


    > Loop
    >    reg_status(i) <= reg_status(i) or flag(i);
    > end loop


    Which of course I just realized I can't do since the index here would
    be an integer and wouldn't match flag_type. grrrr

    Shannon
     
    Shannon, Jun 26, 2009
    #4
  5. Shannon

    Shannon Guest

    On Jun 26, 1:02 pm, Jonathan Bromley <>
    wrote:
    > On Fri, 26 Jun 2009 12:52:08 -0700 (PDT), Shannon wrote:
    > >I was specific about the ordering since I am going to use the flag
    > >array to update a vector where the specific location of each bit is
    > >important (and fixed).

    >
    > In that case, you really DON'T want to use an enum.
    > It gives you no control over the mapping from
    > enum positions to bit positions in the vector.
    >
    > Consider named constants instead.  That gives you
    > the same readable usage, but anchors the flag
    > positions in the std_logic_vector.  It also
    > allows you to create named bit-fields by using
    > subtypes.
    >
    > As an example, suppose you have an 8-bit
    > flag vector laid out like this:
    >
    >   bit 7: flag "f7"
    >   bits 6..5: two-bit control code "cc2"
    >   bit 4:  flag "f4"
    >   bits 3..1: three-bit control code "cc3"
    >   bit 0: flag "f0"
    >
    > Then you could do...
    >
    >   subtype flag_vector_t is std_logic_vector (7 downto 0);
    >   constant f7: positive := 7;
    >   subtype cc2 is positive range 6 downto 5;
    >   subtype code2_t is std_logic_vector(cc2);
    >   constant f4: positive := 4;
    >   subtype cc3 is positive range 3 downto 1;
    >   subtype code3_t is std_logic_vector(cc3);
    >   constant f0: positive := 0;
    >
    >   signal flags: flag_vector_t;
    >   signal code3: code3_t;
    >   signal code2: code2_t;
    >
    >   ...
    >
    >   flags(f0) <= '1';
    >   flags(cc2) <= code2;
    >   code3 <= flags(cc3);
    >   if flags(f0)='1' then ...
    >
    > But of course your flag word is now simply a
    > std_logic_vector, which can freely be copied
    > to or from any other such.
    >
    > There are other games you can play with records,
    > but named constants and subtypes are flexible
    > and painless.  They don't bring you a whole lot
    > of type checking, but there are times when you
    > don't want that anyway.
    > --
    > Jonathan Bromley, Consultant
    >
    > DOULOS - Developing Design Know-how
    > VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
    >
    > Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
    > ://www.MYCOMPANY.com
    >
    > The contents of this message may contain personal views which
    > are not the views of Doulos Ltd., unless specifically stated.


    Thanks Jonathan. This is the reason I posted since I had a sneaking
    suspicion I was making things too hard. You are right of course. I
    would make the "look-up table" more readable anyway:

    constant over_current : positive 1;
    constant over_voltage : positive 2;
    etc...
    rather than having to count your way through and enum (which could get
    reordered by the synth anyway...)

    Thanks.
     
    Shannon, Jun 26, 2009
    #5
  6. Shannon wrote:
    >> Loop
    >> reg_status(i) <= reg_status(i) or flag(i);
    >> end loop

    >
    > Which of course I just realized I can't do since the index here would
    > be an integer and wouldn't match flag_type. grrrr
    >
    > Shannon



    hmmm.
    'pos worked with quartus like this:
    ____________________________________________________________________
    function op2vec (arg : op_t)
    return std_logic_vector is
    variable argn_v : natural;
    -----------------------------------------
    -- type op_t is (ts_load, cal_load, cmd2, cmd3);
    -- 00 01 10 11 -- cal_adr port values
    -----------------------------------------
    begin
    argn_v := op_t'pos(arg);
    return std_logic_vector(to_unsigned(argn_v, adr_len_c));
    end function op2vec;
    ____________________________________________________________________

    -- Mike Treseler
     
    Mike Treseler, Jun 26, 2009
    #6
  7. Shannon

    KJ Guest

    "Shannon" <> wrote in message
    news:...
    > I was specific about the ordering since I am going to use the flag
    > array to update a vector where the specific location of each bit is
    > important (and fixed). Something like:
    >
    > Loop
    > reg_status(i) <= reg_status(i) or flag(i);
    > end loop
    >
    > This flag array is a list of fault bits.


    For processor register maps I prefer to define a record type like this...
    type t_INPUT_DMA_STATUS_PORT is record
    Done: std_ulogic_vector(31 downto 31);
    Reserved: std_ulogic_vector(30 downto 26);
    Current_Count: std_ulogic_vector(25 downto 0);
    end record;

    Then create a pair of functions to convert to and from std_ulogic_vectors
    like this...
    function To_Std_ULogic_Vector(L : t_INPUT_DMA_STATUS_PORT) return
    std_ulogic_vector is
    variable RetVal: std_ulogic_vector(31 downto 0);
    begin
    RetVal := (others => '0');
    RetVal(L.Done'range) := L.Done;
    RetVal(L.Reserved'range) := L.Reserved;
    RetVal(L.Current_Count'range) := L.Current_Count;
    return(RetVal);
    end To_Std_ULogic_Vector;

    function From_Std_ULogic_Vector(L : std_ulogic_vector) return
    t_INPUT_DMA_STATUS_PORT is
    variable RetVal: t_INPUT_DMA_STATUS_PORT;
    variable Lx: std_ulogic_vector(L'length - 1 downto 0);
    begin
    Lx := L;
    RetVal.Done := Lx(RetVal.Done'range);
    RetVal.Reserved := Lx(RetVal.Reserved'range);
    RetVal.Current_Count := Lx(RetVal.Current_Count'range);
    return(RetVal);
    end From_Std_ULogic_Vector;

    All of this goes into a package that goes along with the entity.

    Creating and maintaining these functions as the basic type evolves over time
    is fairly straight forward, in fact changes that involves only the bits
    within an existing field (like making a particular field be two bits wide
    rather than one) involve editing only the type definition to put in the new
    bit definitions, no other edits are needed, just recompile. Adding or
    removing fields only requires editing the record and the to/from functions.
    If there is any code anywhere else in the model that then would be affected
    (such as X.Done <= "1" where the 'Done' field for whatever reason now
    changes to be 2 bits) you don't need to hunt these affected areas down,
    simply recompile and the compiler will flag it for you (in this case the
    complaint being the assignment of a vector of size one to something that is
    two bits wide)...much less tedious.

    Having done that bit of groundwork (which can be somewhat or mostly
    'macro-ized' depending on your fav editor's capabilities) lots of things
    come out looking clean

    Simple assignment:
    Status.Done <= "1";
    Logic operations (such as masking the bits of one reg with another) are
    handled mostly by type conversion using the to/from functions:
    Status <= From_Std_ULogic_Vector(To_Std_ULogic_Vector(Status) and
    To_Std_ULogic_Vector(Mask_Reg));

    When you get around to writing the testbench code for the processor model
    these to/from functions will come in handy yet again since the model for the
    'source code' of the processor will look clean dealing with the record types
    (as above for 'simple assignment') but at some point the basic 'processor
    model' itself will need to communicate via generic std_(u)logic_vectors.
    That I generally wrap up inside a procedure (or function) in process scope
    like this...

    procedure Write_Port(Data: t_INPUT_DMA_STATUS_PORT)

    Do that for each and every software port in your design and the testbench
    processor model reduces down to a whole bunch of simple 'write_port' and
    'read_port' calls without having to even specify addresses of those ports in
    the call since those procedures can be written to contain the address by
    virtue of VHDL's function/procedure overloading. As long as you only have
    one port that is of type 't_INPUT_DMA_STATUS_PORT' the address of the port
    can be defined as a constant in the procedure, so no need to pass it in as a
    parameter as you would with a less general 'write anything' or 'read
    anything' set of procedures. These 'register specific' read and write
    procedures in turn generally call a more basic 'read' or 'write' procedure
    that works with std_(u)logic_vectors that implements whatever the basic
    protocol of a read or write actually is at the signal level (i.e. set strobe
    low, wait 100 ns, drop 'wr_n'...blah, blah...) and works with any address
    and data since it is working at the std_(u)logic_vector level.

    Kevin Jennings
     
    KJ, Jun 27, 2009
    #7
    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. -

    enum within an enum

    -, Jun 12, 2005, in forum: Java
    Replies:
    6
    Views:
    591
  2. Jerminia
    Replies:
    3
    Views:
    659
    Roedy Green
    Oct 7, 2005
  3. dof
    Replies:
    10
    Views:
    723
  4. Shawn W_
    Replies:
    5
    Views:
    320
    Aldric Giacomoni
    Sep 16, 2009
  5. Tomasz Chmielewski

    sorting index-15, index-9, index-110 "the human way"?

    Tomasz Chmielewski, Mar 4, 2008, in forum: Perl Misc
    Replies:
    4
    Views:
    357
    Tomasz Chmielewski
    Mar 4, 2008
Loading...

Share This Page