Address of array provided as std_logic_vector

2019-08-03 10:18发布

问题:

I'm trying to construct a ROM, which has as declaration a : in std_logic_vector(5 downto 0) for the access address. My problem its that I don't know how to access the ROM array with a std_logic_vector, Should I use a cast to integer or what else can I do?

My code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
--------------------------------------------------------------------------------
entity imem is
    GENERIC(CONSTANT N : INTEGER := 32);
    port (a : in std_logic_vector(5 downto 0);
         result : out std_logic_vector(N-1 downto 0));
end imem;


architecture behavior of imem is
    signal addres : integer;
    type memory is array (0 to 64) of std_logic_vector(N-1 downto 0) ;
    constant myrom : memory := (
         2 => x"11111111" , --255
         3 => x"11010101" , 
         4 => x"01101000" , 
         6 => x"10011011" , 
         8 => x"01101101" , 
         9 => x"00110111" , 
         others => x"00000000" ) ;

begin 
    addres <= signed(a);
    result <= memory(addres);

end behavior;

With this code as shown I get the following error:

imem.vhd:25:21: can't match type conversion with type integer  
imem.vhd:25:21: (location of type conversion)
imem.vhd:26:21: conversion not allowed between not closely related types  
imem.vhd:26:21: can't match type conversion with type array type "std_logic_vector"
imem.vhd:26:21: (location of type conversion)
ghdl: compilation error  

回答1:

Assuming that a is an unsigned address value, then you must first cast it to unsigned, and then to integer. Note that the result should access myrom and not memory type. The code can then be:

addres <= to_integer(unsigned(a));
result <= myrom(addres);

And you can even skip the intermediate addres signal and do:

result <= myrom(to_integer(unsigned(a)));

The memory type is also one longer than required, since the 6-bit a input can only cover 0 .. 63, and not 0 .. 64. A better way to declare the memory type would be through use the the 'length attribute for a, like:

type memory is array (0 to 2 ** a'length - 1) of std_logic_vector(N-1 downto 0);


回答2:

ghdl semantics are by default strict -1993 which has an impact on Morten's answer's changes

For:

type memory is array (0 to 2 ** a'length - 1) of 
        std_logic_vector(N-1 downto 0);

we get:

ghdl -a imem.vhdl
imem.vhdl:15:29:warning: universal integer bound must be numeric literal or attribute

Tristan Gingold the author of ghdl authored an Issue Report leading to a Language Change Specification in 2006, which gave explicit permission to then current (-2002) implementations to treat a range with an expression as one bound as convertible to an integer range when the other bound is a universal integer (a literal). The LCS didn't give permission to do the conversion in implementations conforming to earlier versions of the standard. Tristan's ghdl is strictly by the book here and by default is -1993 compliant and generates an error.

There are two ways to deal with the error. Either use the command line option to ghdl during analysis to specify a version of the standard where the range can be converted to type integer or provide the range directly.

From ghdl --help-options we see:

--std=87/93/00/02/08 select vhdl 87/93/00/02/08 standard

Where this command line flag can be passed as in ghdl -a --std=02 imem.vhdl.

Also the range type can be declared directly as in:

type memory is array (natural range 0 to 2 ** a'length - 1) of 
            std_logic_vector(N-1 downto 0);

Both methods of analyzing type memory work.

And the moral of all this is that VHDL is a tightly typed language.

Notes


  1. -2008 compliance is not fully implemented in current versions of ghdl.)
  2. There's historical support for interpreting the standard to support the conversion anyway. The LCS overcomes ambiguity.
  3. See IEEE Std 1076-1993 3.2.1.1 Index constraints and discrete ranges para 2 and IEEE Std-1076-2008 5.3.2.2 Index constraints and discrete ranges para 2.


标签: vhdl ghdl