Yet another question about array indexing

T

tudelftrocks

Hi,

I found several posts about array indexing but I am still confused on
how to use an one-hot address to index the array. The reason why I
want o use a hot-one address is that I have to generate the addresses
myself in another part of the project and therefore there is no need
for an address encoder/decoder if I use the one-hot address. However,
from the posts I read, it seams that I can only index an array with
integer and enumerate types. Is this correct? How can I get avoid the
use of an address encoder/decoder?

In the following code both R_ADR and W_ADR are a 32 bits hot-one
address:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity memory is
generic( addr_width : integer := 5;
data_width : integer := 4);
port(
Q : out std_logic_vector(data_width - 1 downto 0 );
R_ADR : in std_logic_vector(2**addr_width - 1 downto 0); --
This is a hot-one address
W_ADR : in std_logic_vector(2**addr_width - 1 downto 0); --
This is a hot-one address
D : in std_logic_vector(data_width - 1 downto 0 );
W : in std_logic;
R : in std_logic;
ME : in std_logic;
CLK : in std_logic
);
end memory;

architecture synth_mem of memory is
type mem_array is array (std_logic_vector range <>) of
std_logic_vector(data_width - 1 downto 0 );
signal ram : mem_array(2**addr_width - 1 downto 0);

begin
process (ME, CLK)
begin
if ME = '1' then
Q <= (others => '1');
elsif CLK'event and CLK = '1' then
if R = '1' then
Q <= ram(R_ADR);
else
Q <= (others => '1');
end if;
if W = '1' then
ram(W_ADR) <= D;
end if;
end if;
end process;

end synth_mem;

I have the following errors:
Entity <memory> compiled.
ERROR:HDLParsers:201 - "RTL/memory.vhdl" Line 25. Array index subtype
std_logic_vector is not a discrete range.
ERROR:HDLParsers:3312 - "RTL/memory.vhdl" Line 26. Undefined symbol
'mem_array'.
ERROR:HDLParsers:1209 - "RTL/memory.vhdl" Line 26. mem_array:
Undefined symbol (last report in this block)
ERROR:HDLParsers:3313 - "/RTL/memory.vhdl" Line 56. Undefined symbol
'ram'. Should it be: rem?
ERROR:HDLParsers:1209 - "RTL/memory.vhdl" Line 56. ram: Undefined
symbol (last report in this block)

How can I use an one-hot address to index my array?

Thank you in advance.
 
T

Tricky

The reason why I
want o use a hot-one address is that I have to generate the addresses
myself in another part of the project and therefore there is no need
for an address encoder/decoder if I use the one-hot address.

There may not be on the write side, but the read side has a massive
Mux. This will be ok for small numbers of address lines, but it will
get very slow very quickly.

How can I use an one-hot address to index my array?

Thank you in advance.

Short answer : you cant without a decoder. using a one hot address bus
really just gives you a load of registers with each one hot write
address line connected to the enable on the appropriate register. Its
the read address that then becomes a problem, because the output will
be a large one hot mux, which is just a long chain of 2-1 muxes, that
you will have to define yourself.

Array's in VHDL are always indexed using integers. And so it's easiest
to have the addresses as an integer. They also map nicely to internal
memory blocks. A Std_logic_vector is NOT an integer, its just an array
of bits. I recommend using ieee.numeric_std.all instead of
ieee.std_logic_unsigned.all (this package is NOT an ieee standard and
different vendors implement it differently, whereas numeric_std IS a
standard).

if you REALLY wanted to use one hot addressing, you could use
something like the following (all code assumed address_width = 5 and
data width = 4):

process (CLK)
function find_value_1hot(a : std_logic_vector; mem : mem_array)
return std_logic_vector is
variable ret_slv : std_logic_vector(3 downto 0) := (others =>
'1');
begin
for i in a'range loop
if a(i) = '1' then
ret_slv := mem(i);
end if;
end loop;

return ret_slv;
end function find_value_1hot;

begin
if rising_edge(clk) then
if R = '1' then
Q <= find_value_1hot(R_ADR, ram);
else
Q <= (others => '1');
end if;


ram_write : for i in ram'range loop
if W = '1' and W_ADR(i) = '1' then
ram(i) <= D;
end if;
end loop ram_write;
end if;
end process;

From synthesis and timing analysis, the Q output mux was one large mux
chain, as expected. The fmax was 284MHz.

I then tried the following (using the numeric_std_package, not
std_logic_unsigned):

process (CLK)
begin
if rising_edge(clk) then
if R = '1' then
Q <= ram( to_integer( unsigned(R_ADR) ));
else
Q <= (others => '1');
end if;


if W = '1' then
ram( to_integer(unsigned(w_adr) )) <= D;
end if;
end if;
end process;

No surprises, the synthesisor built a ram primitive. And the FMax is
now 356Mhz, about 50% faster than the other method.

Dont be worried about address decoders. They are very common, used
alot and easy to understand. When you start doing things 1-hot it
starts getting a little less clear about whats going on.
 
T

tudelftrocks

The first question is: are you sure this is actually what you want to
do?  The answer to that question depends on what you envision the
actual hardware implementation of this thing looking like (assuming
that this code is meant to one day see hardware).  If you're planning
to try to implement this in a real RAM, then the decoding functionality
is hardwired into the RAM block.  I suppose you CAN use a RAM in which
the address is always a one-hot value, but it means throwing away the
vast majority of it.

If, on the other hand, your intended result is a register file of
discrete flip-flops with selection logic on the input and output sides
of things, this is a reasonable way to be attacking the problem.  If
that's the case, the decision to declare your address widths to be
powers of two long is something of a strange one, but I digress.  If
that's the implementation you're looking to generate, then look into
using a process with a for loop to AND each register with it's
selector, then OR the results together.  Note that this approach will
rapidly become unwieldly for any serious number of registers.

--
Rob Gaddi, Highland Technology
Email address is currently out of order
- Hide quoted text -

- Show quoted text -
Hi,

Thank you for your answer. Yes, I am sure that is what I want to do.
the memory sizes I need can be quite small, so the option of using
a real RAM will take more area then using a "synthesizable" memory.
Moroever, because I generate my own addresses I do not need a decoder
therefore taking even less area than a real RAM implementation.

Your idea of using a for loop seams interesting but I got a bit lost
on
how to actually code this. Could you please explain a bit more what
you
mean with AND the register and the selector? From the code I sent you
mean:
D AND W_ADR?

Could you please also elaborate on why you consider the option of
using a
hot-one address a strange one? From which point of view do you mean?

Thanks.

Filipa
 
K

KJ

Hi,

I found several posts about array indexing but I am still confused on
how to use an one-hot address to index the array.

The same way you would use any other vector, by converting it to an integer.
address_integer <= to_integer(unsigned(my_one_hot_address_vector));

This doesn't 'cost' anything in terms of logic resources, it is simply
applying a specific interpretation (i.e. integer) to something that is
defined to be another type (presumalbly your one hot address is
std_logic_vector).
However,
from the posts I read, it seams that I can only index an array with
integer and enumerate types. Is this correct?

Yes, arrays can only be indexed by discrete types, integers and enumerations
being the ones most commonly used.
How can I get avoid the
use of an address encoder/decoder?

The encoder doesn't cost anything in terms of generated logic resources. A
collection of arbitrary bits can always be interpreted as an integer number
without it generating any logic. It is simply a type conversion operation
that is required by the language because from a language perspective it
requires proper conversion when things are of different types. This does
not imply though that these conversions generate any logic in synthesized
code.

The fact that your address is 'one hot' is totally irrelevant to using it to
address the memory. The fact that you choose to only read/write N addresses
out of a possible 2**N doesn't factor into the implementation at all.

Kevin Jennings
 
A

Andy

if you REALLY wanted to use one hot addressing, you could use
something like the following (all code assumed address_width = 5 and
data width = 4):

process (CLK)
    function find_value_1hot(a : std_logic_vector; mem : mem_array)
return std_logic_vector is
      variable ret_slv : std_logic_vector(3 downto 0) := (others =>
'1');
    begin
      for i in a'range loop
        if a(i) = '1' then
          ret_slv := mem(i);
        end if;
      end loop;

      return ret_slv;
    end function find_value_1hot;

The problem with converting the one-hot address to an integer-encoded
index is that the synthesis tool does not know that only one bit in a
() is set, i.e. that a() is mutually exclusive. So prioritization
logic is inserted for you. As written the rightmost set bit in a()
will determine which element of mem is returned.

To avoid this, you have to create an and-or mux, or use a tri-state
assignment such that, when converted to a mux, the synthesis tool can
assume the tri-state enables are mutually exclusive.

And-or priority-less mux:
variable temp : std_logic_vector(mem(0)'range) := (others => '0');
....
for i in a'range loop
temp := temp or ((mem(i)'range => a(i)) and mem(i));
end loop;
return temp;

Or for a tri-state approach that will be converted to a mux (must be a
concurrent generate statement, so it won't work in a function):

ts: for i in a'range generate
output <= mem(i) when a(i) = '1' else (others => 'Z');
end generate;

For tri-state buses to work (or be converted to priority-less muxes)
each conditional assignment must be a separate concurrent statement,
not sequential statements.

In some ways the t-state version is easier to understand, but it also
requires the reader to understand that no real tri-state signals are
being used, it will all get converted to mux logic. It also cannot be
implemented in a function or procedure.

Andy
 
M

Mike Treseler

Andy said:
And-or priority-less mux:
variable temp : std_logic_vector(mem(0)'range) := (others => '0');
...
for i in a'range loop
temp := temp or ((mem(i)'range => a(i)) and mem(i));
end loop;
return temp;

So how does this compare with Tricky's
second example in synthesis?

-- Mike Treseler
 
K

KJ

In some ways the t-state version is easier to understand, but it also
requires the reader to understand that no real tri-state signals are
being used, it will all get converted to mux logic. It also cannot be
implemented in a function or procedure.

For an example of an encoding method that does not prioritize hark
back to the overly windy "New keyword 'orif' and its implications"
thread in this group from Sep, 2007

http://groups.google.com/group/comp...st&q=encoding+Kevin+Jennings#403697772e2d7f94

From there is an example of 8->3 encoding (shown below) that can be
implemented in a function and can be generalized to work with other
bit widths as well and will be implemented in minimal logic.

Encoded_OneHotInps(0) <= OneHotInps(1) xor OneHotInps(3) xor
OneHotInps(5) xor OneHotInps(7);
Encoded_OneHotInps(1) <= OneHotInps(2) xor OneHotInps(3) xor
OneHotInps(6) xor OneHotInps(7);
Encoded_OneHotInps(2) <= OneHotInps(4) xor OneHotInps(5) xor
OneHotInps(6) xor OneHotInps(7);

Kevin Jennings
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top