Constant conversion (natural to std_logic_vector)

A

a1_nocrap_exh

I am in a situation where I have to increase an address bus width in
bit of re-usable code.

In a package there is a list of constants which are used in the address
decode

constant abus_width : natural := 5;
constant REGISTER_A : std_logic_vector(abus_width-1 downto 0) :=
"00001";
constant REGISTER_B : std_logic_vector(abus_width-1 downto 0) :=
"00010";
etc.

I've now increased abus_width by 2 and now all the constant literals
need updating because they are the wrong width.

I thought I would try to work out a way of specifying the constants so
that they would grow with abus_width so that if we ever had to do this
again it would automatically work e.g.

library ieee;
use ieee.std_logic_arith.all;

constant abus_width : natural := 7;
constant REGISTER_A : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#01#,abus_width);
constant REGISTER_B : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#02#,abus_width);

However I now get the following warning "Case choice must be a locally
static expression." in the Case statements which use these constants.

But it IS locally static isnt it? It's a constant, it's in a package,
that package is referenced...

Anyone ever done anything like this before or got a better technique?

Regards

Alex Holland
 
A

a1_nocrap_exh

I cannot use VHDL 93's HEX literal ( X'"AA" ) because my bus is not a
multiple of 4-bits wide.
 
A

a1_nocrap_exh

Sorry, that's the way it is.

Thanks for the link. But in this situation I am not doing anything
fancy. These ARE constants. It should work.
A case expression is limited to operands that are scalar

But they are scalar, that is my point.

If I store my constants as naturals, and convert my std_logic_vector
signal to integer EVERYTHING works e.g.

constant REGISTER_A : natural := 1;
constant REGISTER_B : natural :=2;

case conv_integer(unsigned(addr)) is

when REGISTER_A =>

when REGISTER_B =>

when OTHERS =>

end case;

So I dont understand why I cannot store my constants as
std_logic_vectors that are pre-converted from naturals?

constant abus_width := 5;

constant REGISTER_A : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#01#, abus_width);

constant REGISTER_B : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#02#, abus_width);

case addr is

when REGISTER_A =>

when REGISTER_B =>

when OTHERS =>

end case;

I would switch to storing them as naturals, but the code containing the
case statement has already been to silicon, dont really want to change
anything in that file if I can help it.

I think I *will* find the syntax to make this warning go away.

Anyone?

Alex Holland
 
C

Charles, NG

You may find it easier if you use subtypes: e.g.

use ieee.numeric_std.all;
.. . . . .
subtype abus_type_t is std_logic_vector(7 downto 0);
.. . . . .
constant abus_sig_s : abus_type_t :=
std_logic_vector(to_unsigned(2, abus_type_t'length));

Then you only have to change the subtype dimensions in a single place if
your bus gets resized

Regards,
Charles
 
A

a1_nocrap_exh

use ieee.numeric_std.all;
. . . . .
subtype abus_type_t is std_logic_vector(7 downto 0);
. . . . .
constant abus_sig_s : abus_type_t :=
std_logic_vector(to_unsigned(2, abus_type_t'length));

Then you only have to change the subtype dimensions in a single place if
your bus gets resized

Not that it matters but you dont have to use subtypes to only need to
change dimensions in a single place, look at my example I posted
earlier (or below), you change one constant "abus_width" and voila.

constant abus_width : natural := 7;

constant REGISTER_A : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#01#,abus_width);

constant REGISTER_B : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#01#,abus_width);

I've used std_logic_arith rather than numeric_std... I wonder if that
helps? I doubt it.

Charles, can you use a constant defined your way in a CASE statement?

Alex Holland
 
M

Mike Treseler

Thanks for the link. But in this situation I am not doing anything
fancy. These ARE constants. It should work.

It probably should, but it doesn't and this is a FAQ.

-- Mike Treseler
 
M

Marcus Harnisch

Alex,

I thought I would try to work out a way of specifying the constants so
that they would grow with abus_width so that if we ever had to do this
again it would automatically work e.g.

library ieee;
use ieee.std_logic_arith.all;

constant abus_width : natural := 7;
constant REGISTER_A : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#01#,abus_width);
constant REGISTER_B : std_logic_vector(abus_width-1 downto 0) :=
conv_std_logic_vector(16#02#,abus_width);

You can either extend your registers widths to a multiple of 4 and use
the VHDL'93 syntax. In the case-statement you would have to extend the
case-expression to the same width and be done. Chances are that
Synthesis will strip the unused bits anyway.

Or, as someone else already noted, you could use if-elsif*-else
chains. Synthesis tools are also pretty good at generating the
expected logic in cases like this.

Alternatively you could assign the registers like this

constant REGISTER_A : std_logic_vector(abus_width-1 downto 0)
:= (0 => '1', others => '0');
constant REGISTER_B : std_logic_vector(abus_width-1 downto 0)
:= (1 => '1', others => '0');

(Actually I am not absolutely sure that this last assignment works as
expected. You'd have to try that yourself.)
But it IS locally static isnt it? It's a constant, it's in a package,
that package is referenced...

Not quite. Locally static expressions must be fixed at compile
time. Functions, such as `conv_std_logic_vector', defined in package
bodies are not. You could compile a different package body for
std_logic_arith with completely different function definitions and be
screwed.

Best regards,
Marcus
 
A

a1_nocrap_exh

Hi Marcus,

Thanks for the reply, good suggestion for your alternative
Not quite. Locally static expressions must be fixed at compile
time. Functions, such as `conv_std_logic_vector', defined in package
bodies are not. You could compile a different package body for
std_logic_arith with completely different function definitions and be
screwed.

Ah, yes now I understand. It ISNT the case statement which needs to
resolve at compile time it's the WHEN operator. That is why I can
define my constants as naturals and convert my case argument to an
integer and it compiles fine e.g.

constant REGISTER_A : natural := 1;
constant REGISTER_B : natural := 2;

case conv_integer(unsigned(addr)) is

when REGISTER_A =>

when REGISTER_B =>

when OTHERS =>

end case;

Makes sense now, dont like it, but it makes sense.

Alex
 
A

Andy

The best approach I have found for address decoding registers on
adjacent addresses is to define the registers as an array of SLV (or
integer or unsigned or whatever), then convert the address to integer,
and index the array with that. No case or if/elsif statements
required. Pad the array to hold an integral power of two registers, and
use mod on the index to ensure legal indices (synthesis will optimize
out the unused registers). As an added bonus, if the synthesis tool
can determine that your design only accesses one or two registers in
any clock period, it can infer single or dual port ram for them.

Whenever I see a long case or if/elsif tree with numeric targets, I
think "can I use an array and/or loop here?"

Hope this helps,

Andy
 

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

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top