Assigning Values to Enumerated Types

K

Kevin Neilson

This seems simple, but I've been unable to find the answer. I have an
enumerated type like this:

type opmode_type is (m, p_plus_m, p_minus_m, m_plus_c...);
signal opmode : opmode_type;

As I understand it, the synthesizer will assign sequential values to
these (i.e., m=1, p_plus_m=2). But I need to assign particular (3-bit
signed) values to these: e.g., m="101", p_plus_m="110". Is there a way
to do this?

Perhaps I need to do something else entirely. I supposed I could use
aliases to assign names to the constants. I could make a constant array
and somehow index it (maybe with the enumerated type?). Or maybe I
could make a record?

type opmode_type is record m, p_plus_m, ... : unsigned(2 downto 0);
signal opmode : opmode_type := ("101","110",...);

and then access the opmode with a field, as in: opmode.p_plus_m

I just wondered what is most stylistically proper way to do this.
-Kevin
 
K

KJ

Kevin Neilson said:
This seems simple, but I've been unable to find the answer. I have an
enumerated type like this:

type opmode_type is (m, p_plus_m, p_minus_m, m_plus_c...);
signal opmode : opmode_type;

As I understand it, the synthesizer will assign sequential values to these
(i.e., m=1, p_plus_m=2). But I need to assign particular (3-bit signed)
values to these: e.g., m="101", p_plus_m="110". Is there a way to do
this?

Not really. By using the enumerated type you're in a sense divorcing
yourself from particular encodings...but read on.
Perhaps I need to do something else entirely. I supposed I could use
aliases to assign names to the constants. I could make a constant array
and somehow index it (maybe with the enumerated type?). Or maybe I could
make a record?

type opmode_type is record m, p_plus_m, ... : unsigned(2 downto 0);
signal opmode : opmode_type := ("101","110",...);

and then access the opmode with a field, as in: opmode.p_plus_m

I just wondered what is most stylistically proper way to do this.

Typically I would create a to_std_logic_vector and from_std_logic_vector
function pair to convert between enumerated types and particular bit
encodings (or records...very useful for bits in a read/write port). In your
case, maybe you want a to_unsigned/from_unsigned pair. In any case, with
the to/from functions in hand, you are basically free to use whatever form
is appropriate.

Sample conversion function:

to_unsigned(L: opmode_type) return unsigned is
variable RetVal: unsigned(2 downto 0);
begin
case L is
when m => RetVal := "101";
when p_plus_m => ...
...
end case;
return(RetVal);
end function to_unsigned;

Sample usage:

opmode <= from_unsigned("101");

The conversion functions synthesize quite nicely, there is no 'overhead' in
the final hardware to using it. The appearance and maintainability of the
code is greatly enhanced by converting to/from required bit patterns in this
fashion.

Kevin Jennings
 
T

Tricky

This seems simple, but I've been unable to find the answer. I have an
enumerated type like this:

type opmode_type is (m, p_plus_m, p_minus_m, m_plus_c...);
signal opmode : opmode_type;

As I understand it, the synthesizer will assign sequential values to
these (i.e., m=1, p_plus_m=2). But I need to assign particular (3-bit
signed) values to these: e.g., m="101", p_plus_m="110". Is there a way
to do this?

Perhaps I need to do something else entirely. I supposed I could use
aliases to assign names to the constants. I could make a constant array
and somehow index it (maybe with the enumerated type?). Or maybe I
could make a record?

type opmode_type is record m, p_plus_m, ... : unsigned(2 downto 0);
signal opmode : opmode_type := ("101","110",...);

and then access the opmode with a field, as in: opmode.p_plus_m

I just wondered what is most stylistically proper way to do this.
-Kevin

As KJ said, using an ennumerated type is letting the synthesizer chose
the encoding for you. By default, this is usually done one hot, but I
think there are options to change the encoding, maybe even force it
yourself (I have never done this), but this would be a bit convoluted.

Personally, I would just define opmode_type as a subtype of
std_logic_vector so you have a fixed bit width, and then define
constants for all of the states you want. When using the opmode,
remember to have an "OTHERS" case to catch opmode in any states you
havent defined (although it should never happen).
 
M

Mike Treseler

Brian said:
my_value <= val_of(opmode);


in a similar vein:

type op_t is (run, pause, idle, test, stop, etc)
constant adr_len_c : natural := 3;
subtype adr_t is std_logic_vector(adr_len_c-1 downto 0);
-----------------------------------------------------
function vec2mode (arg : adr_t)
return op_t is
variable index : natural := to_integer(unsigned(arg));
begin
return op_t'val(index);
end function vec2mode;
-----------------------------------------------------
variable op_v : op_t; -- address register enum
-- ...
op_v := vec2mode(my_port_adr);
case op_v is
when run =>
when etc =>
....

-- Mike Treseler
 
K

Kevin Neilson

Brian said:
Don't forget the enumerated type is a range, so it can address an array
of constants.

So use the enumeration, and the synth tool will use its own values for
internal purposes, but where you need your specific values, get them by
using hte enumeration to address the array.

type opmode_val is signed(2 downto 0);
-- from numeric_std, NOT std_logic_signed of course

constant val_of is array (opmode_type) of opmode_val
:= ("101", ...):
signal my_val : opmode_val;

and use an array lookup where KJ used a function (the syntax is
identical for a very good reason!)

my_value <= val_of(opmode);

- Brian
Thanks to all for the answers. I'll probably use the scheme described
above. I can't really just convert the enumerated signal directly to a
value because I only have opmodes for a subset of the numbers, so the
above scheme probably works the best. It also seems reasonably clear.
-Kevin
 
D

David R Brooks

Mike said:
in a similar vein:

type op_t is (run, pause, idle, test, stop, etc)
constant adr_len_c : natural := 3;
subtype adr_t is std_logic_vector(adr_len_c-1 downto 0);
-----------------------------------------------------
function vec2mode (arg : adr_t)
return op_t is
variable index : natural := to_integer(unsigned(arg));
begin
return op_t'val(index);
end function vec2mode;
-----------------------------------------------------
variable op_v : op_t; -- address register enum
-- ...
op_v := vec2mode(my_port_adr);
case op_v is
when run =>
when etc =>
....
But (if you're using it) remember that XST doesn't support 'val
 
K

Kevin Neilson

Brian said:
Don't forget the enumerated type is a range, so it can address an array
of constants.

So use the enumeration, and the synth tool will use its own values for
internal purposes, but where you need your specific values, get them by
using hte enumeration to address the array.

type opmode_val is signed(2 downto 0);
-- from numeric_std, NOT std_logic_signed of course

constant val_of is array (opmode_type) of opmode_val
:= ("101", ...):
signal my_val : opmode_val;

and use an array lookup where KJ used a function (the syntax is
identical for a very good reason!)

my_value <= val_of(opmode);

- Brian

I also found an old post from Mike T where he shows how to initialize
the constant array by name instead of order. Here is my implementation:

type opmode_type is (m, minus_m, p_plus_m, p_minus_m, c_plus_m,
c_minus_m);
type opmode_array is array(opmode_type) of std_logic_vector(6 downto 0);
constant conv_dsp48e_opmode : opmode_array :=
(m => "0000101",
minus_m => "0000101",
p_plus_m => "0100101",
p_minus_m => "0100101",
c_plus_m => "0110101",
c_minus_m => "0110101",
others => (others=>'0'));

-Kevin
 
M

Mike Treseler

Kevin said:
type opmode_type is (m, minus_m, p_plus_m, p_minus_m, c_plus_m,
c_minus_m);
type opmode_array is array(opmode_type) of std_logic_vector(6 downto 0);
constant conv_dsp48e_opmode : opmode_array :=
(m => "0000101",
minus_m => "0000101",
p_plus_m => "0100101",
p_minus_m => "0100101",
c_plus_m => "0110101",
c_minus_m => "0110101",
others => (others=>'0'));

Yes, I like enumeration arrays as a register type.
Looping through a name range is a nice way
to match up groups of register array elements
for assignments.

However, I agree with KJ and leave state encoding to synthesis.
If I care about a state value, then I must
be using it as an output rather than a mode.

The example above is a good demonstration of one downside.
There is no compile time check that the state values
are unique. That is a tough bug to find.

-- Mike Treseler
 
K

Kevin Neilson

Brian said:
I believe these aren't actually state encodings, but control signals to
another block, whose design is not under Kevin's control (a Xilinx
DSP48).

Therefore he (a) may not have the option, and (b) the duplicate code may
actually be correct.

- Brian
That's correct. The enumerated type is a DSP48 "generic" opmode which
gets resolved to a specific opmode depending upon the Xilinx family.
This is defined by the silicon. And the duplicates are correct--the
generic opmode is converted into a specific opmode, alumode, and
subtract flag, and the combination of these is unique for each generic
opmode. -Kevin
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top