Yet another question about array indexing

Discussion in 'VHDL' started by tudelftrocks@gmail.com, Nov 26, 2008.

  1. Guest

    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.
     
    , Nov 26, 2008
    #1
    1. Advertising

  2. Tricky Guest

    > 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.
     
    Tricky, Nov 27, 2008
    #2
    1. Advertising

  3. Guest

    On Nov 26, 6:16 pm, Rob Gaddi <> wrote:
    > On Wed, 26 Nov 2008 08:00:09 -0800 (PST)
    > wrote:
    > > 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.

    >
    > 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
     
    , Nov 27, 2008
    #3
  4. KJ Guest

    <> wrote in message
    news:...
    > 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
     
    KJ, Nov 27, 2008
    #4
  5. Andy Guest

    On Nov 27, 3:47 am, Tricky <> wrote:
    >
    > 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
     
    Andy, Dec 2, 2008
    #5
  6. Andy wrote:

    > 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
     
    Mike Treseler, Dec 2, 2008
    #6
  7. KJ Guest

    On Dec 2, 3:19 pm, Andy <> wrote:

    > 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
     
    KJ, Dec 3, 2008
    #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. C
    Replies:
    0
    Views:
    514
  2. Emin
    Replies:
    4
    Views:
    418
    Paul McGuire
    Jan 12, 2007
  3. Berehem
    Replies:
    4
    Views:
    568
    Lawrence Kirby
    Apr 28, 2005
  4. Skybuck Flying
    Replies:
    30
    Views:
    1,124
    Bill Reid
    Sep 19, 2011
  5. C
    Replies:
    3
    Views:
    233
    Manohar Kamath [MVP]
    Oct 17, 2003
Loading...

Share This Page