Address of array provided as std_logic_vector - vhdl

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

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);

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
-2008 compliance is not fully implemented in current versions of ghdl.)
There's historical support for interpreting the standard to support the conversion anyway. The LCS overcomes ambiguity.
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.
Tristan has since changed the --std= options eliminating -2000 compliance as well as the default standard to 93c which introduces a set of standard relaxations to more closely match industry practices of VHDL tool vendors. The user of a more recent version of ghdl can use --std=93 for strict standard compliance. The issue originally hinged on the VASG (VHDL Analysis and Standardization Group) sponsored by DAC not being allowed to issued Interpretations of standards after -1987. It's safe to say there is no single implementation of any VHDL standard that completely adheres to a particular revision.

Related

std_logic_vector to constant natural in VHDL

I am using NUMERIC_STD library. The incoming PORT signal is RAM_BYTE_EN to be converted as constant integer number RAM_WIDTH.
'''
RAM_BYTE_EN : IN std_logic_vector(3 downto 0); -- Value "0100" passed as RAM_BYTE_EN
constant RAM_WIDTH : natural := to_integer(unsigned(RAM_BYTE_EN)); --convert RAM_BYTE_EN
'''
In simulation, the value RAM_WIDTH is ZERO and not 4.
Don't understand why the conversion is not working. What am I missing?
In simulation, the value RAM_WIDTH is ZERO and not 4.
Setting aside for the moment the anticipated synthesis of an unseen design unit and/or hierarchy and focus on simulation:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rambyteenab is
port (
RAM_BYTE_EN : IN std_logic_vector(3 downto 0) -- Value "0100" passed as RAM_BYTE_EN -- struck semicolon
);
end entity;
architecture foo of rambyteenab is
constant RAM_WIDTH : natural := to_integer(unsigned(RAM_BYTE_EN)); -- convert RAM_BYTE_EN
begin
process
begin
report "RAM_WIDTH = " & integer'image(RAM_WIDTH);
wait;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity higher_in_hierarchy is
end entity;
architecture working of higher_in_hierarchy is
signal RAM_BYTE_ENAB: std_logic_vector(3 downto 0) := "0100";
begin -- RAM_BYTE_ENAB is "0100" when inst is elaborated
inst:
entity work.rambyteenab
port map (RAM_BYTE_EN => RAM_BYTE_ENAB);
end architecture;
architecture failing of higher_in_hierarchy is
signal RAM_BYTE_ENAB: std_logic_vector(3 downto 0);
begin -- STATEMENTS ELBORATED in order
inst:
entity work.rambyteenab
port map (RAM_BYTE_EN => RAM_BYTE_ENAB);
concurrent_signal_assignment:
RAM_BYTE_ENAB <= "0100";
end architecture;
By analyzing the above four design units and either using a configuration specification or configuration declaration or elaboration time command line options to specify which architecture of higher_in_hierarchy to use with a declaration of signal RAM_BYTE_ENAB used as an actual in associating the port RAM_BYTE_EN of entity rambyteenab we can demonstrate it's possible to rely on the value of a port signal of mode in at elaboration time.
It depends on the port signal having been initialized to a useful value and elaboration order guaranteeing that value prior to it's evaluation.
All four design units are found in order in the same design file which is analyzed into a reference library (work):
ghdl -a rambyteenab.vhdl
The target architecture of higher_in_hierarchy is elaborated separately using both architectures:
ghdl -e higher_in_hierarchy failing
ghdl -e higher_in_hierarchy working
Note that elaborating higher_in_hierarchy without specifying the architecture would result in using the architecture working, which is the last analyzed architecture, working being used by default.
These produce elaborated design hierarchies:
%: ls -aF higher*
/Users/user16145658/Desktop
-rwx--x--x 1 user16145658 staff 1270312 Feb 2 05:32 higher_in_hierarchy-failing*
-rwx--x--x 1 user16145658 staff 1269544 Feb 2 05:33 higher_in_hierarchy-working*
which can be used to demonstrate the ability to use elaboration order and initialization value to pass the value of a signal to be used in the elaboration of a constant, at elaboration time:
%: higher_in_hierarchy-working
rambyteenab.vhdl:16:9:#0ms:(report note): RAM_WIDTH = 4
%: higher_in_hierarchy-failing
../../src/ieee/v93/numeric_std-body.vhdl:2098:7:#0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
rambyteenab.vhdl:16:9:#0ms:(report note): RAM_WIDTH = 0
%:
The failure is by virtue of RAM_BYTE_ENAB having a a default initialization of all 'U's which generates the numeric_std warning assertion in simulation. The OP should have encountered a similar warning during simulation as the only means of producing a zero through elaboration.
So, what about synthesis?
Historically IEEE Std 1076.6-2004 VHDL Register Transfer Level (RTL) Synthesis (withdrawn due to lack of vendor participation and age) for RAM_BYTE_ENAB told us:
8.4.3.1 Object declarations
b) Signal declarations
...
The initial value expression shall be ignored unless the declaration is in a package, where the declaration shall have an initial value expression.
which didn't allow for depending on the initial value, a practice supported generally in memory based FPGAs today. Some number of tool implementations for target device architectures not capable of passing initial values through lack of passing memory or ability to otherwise pull up or pull down nets still do not make use of initial values.
The reliance on initial values isn't possible in a portable fashion.
Constants should be known at synthesis time and cannot be derived from signals. For the RAM to be instantiated, its width needs to be known. So you should set it to a constant number e.g.
constant RAM_WIDTH : natural := 32;

write on invalid address to RAM in VHDL, Verilog, sim behaviour

Lets have a BRAM or any other memory under Verilog or VHDL.
For example this:
module raminfr (clk, we, a, di, do);
input clk;
input we;
input [4:0] a;
input [3:0] di;
output [3:0] do;
reg [3:0] ram [31:0];
always #(posedge clk) begin
if (we)
ram[a] <= di;
end
assign do = ram[a];
endmodule
Now lets assume that we have already write valid data to "ram".
Does simulators invavalidate all items in "ram" if address "a" will have invalid value (4'bxxxx) ("we"=1 and clk will have posedge)?
Or it lets values in ram as they were?
For Verilog
The IEEE Std 1800-2009 SystemVerilog standard subsumed both the IEEE Std 1364-2005 Verilog standard and the IEEE Std 1800-2005 SystemVerilog standard. The IEEE Std 1800-2012 SystemVerilog standard supplanted the -2009 version.
See IEEE Std 1800-2012 7.4.6 Indexing and slicing of array:
If an index expression is out of bounds or if any bit in the index expression is x or z, then the index shall be invalid. Reading from an unpacked array of any kind with an invalid index shall return the value specified in Table 7-1. Writing to an array with an invalid index shall perform no operation, with the exceptions of writing to element [$+1] of a queue (described in 7.10.1) and creating a new element of an associative array (described in 7.8.6). Implementations may issue a warning if an invalid index occurs for a read or write operation on an array.
For VHDL
An equivalent VHDL design description might be:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity raminfr is
port (
clk: in std_logic;
we: in std_logic;
a: in std_logic_vector(4 downto 0);
di: in std_logic_vector(3 downto 0);
do: out std_logic_vector(3 downto 0)
);
end entity;
architecture behave of raminfr is
type ram_type is array (0 to 15) of std_logic_vector (3 downto 0);
signal ram: ram_type;
begin
process (clk)
begin
if rising_edge(clk) then
if we = '1' then
ram(to_integer(unsigned(a))) <= di;
end if;
end if;
end process;
do <= ram(to_integer(unsigned(a)));
end architecture;
Where the numeric_std package to_integer function is used to convert the array value of a to an integer index. (VHDL is a bit more flexible here, array indexes can either be integer types or enumerated types, together referred to as discrete types).
Reading the source for to_integer we see it will convert an input unsigned array value containing an 'X' to all 'X's and the 'LEFT value of that being 'X' will return a natural integer subtype value of 0 and optionally report that:
if (XARG(XARG'left) = 'X') then
assert NO_WARNING
report "NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0"
severity warning;
return 0;
end if;
These warnings can be disabled implementation wide by changing the value of NO_WARNING which is locally static. Using to_integer (or with Synopsys package std_logic_arith and function conv_integer) the index will be 0.
Additionally VHDL implementations have the ability to stop simulation on severity warning reports.
While you could handle the result of an assignment with an index provided as an array value differently in (as in 2, 4, 8, 16 or 32 invalidated memory locations depending on the number of 'X' element values of a here), you've already compromised the integrity of your design model state and some corrective should be taken before counting on the simulation results for either a SystemVerilog or VHDL design model.
The overhead of complex fiddling doesn't seem worthwhile in general. These warnings are of a class of warnings that should be reviewed before synthesis.
These warning can occur before array values are reset when their default initial values are metavalues. You can prevent that in most FPGA designs by initializing a and any predecessors so a contains a binary representing value or simply ignoring reports at time 0 before a reset takes affect.
You can also prevent the write to address 0 by initializing we and any predecessor(s) to '0'.
Simulator will not invalidate anything. Instead the write will be ignored.
For reads in such a situation, it will return 'x' though.

Why couldn't I convert this integer into a logic_vector?

I have been trying to convert this Signal of type integer into an std_logic vector and assign the converted value into another signal that has the same width as a VHDL integer
signal temp : std_LOGIC_VECTOR(31 downto 0) := (others => '0');
signal FrameCumulative : integer :=0;
temp <= to_stdlogicvector(to_unsigned(FrameCumulative));
However I get this error:
Error (10346): VHDL error at vga.vhd(107): formal port or parameter
"SIZE" must have actual or default value
I am using use IEEE.NUMERIC_STD.ALL; and use IEEE.STD_LOGIC_1164.ALL;
First I made the mistake of not checking the integer size within VHDL and tried to assign an integer into a 14-bit vector but after I gave it some thought I relised my mistake.
Now according to many on-line resources, what I am doing should work but my synthesiser complains about it.
If you do know the cause for this would you mind ellaborating on your answer rather than just posting the correct code, Thanks!
The function to_unsigned must be provided with a parameter specifying the width of the vector that you want it to produce. The function to_stdlogicvector is also not the correct thing to be using. Your line should look like this:
temp <= std_logic_vector(to_unsigned(FrameCumulative, temp'length));
The function to_unsigned is a conversion function, it must be provided with the target width. Here, as suggested by #BrianDrummond, the width is specified by taking the length attribute from the target vector itself (temp). The std_logic_vector is a type cast, where the unsigned value is simply interpreted directly as an std_logic_vector.

convert hex number to std_logic_vector

I have a question on converting a hex number into a std_logic_vector. I need the bit representation of the hex numbers because they are my data the simulated keyboard is sending to my board (later). At now i am in development phase:
Here is the code example that doesn't work within ISE:
Subtype ScanCode is std_logic_vector(39 downto 0);
variable binaryRep : ScanCode;
binaryRep := std_logic_vector(16#70F070#);
the conversion in the last line is where the problem appears the Compiler tells me Cannot convert type universal_integer to type std_logic_vector
I have also tried that code but got another error i don't understand
binayRep <= to_stdlogicvector(x"FC");
this was the error message i got:
Near to_stdlogicvector ; 2 visible identifiers match here
I also searched the web for other solutions but i couldn't solve the problem.
Has anyone an Idea how to fix the code ?
16#70F070# is a numerical literal and isn't appropriate directly, it needs a conversion routine. You don't have an appropriate conversion routine that matches the signature [integer return std_logic_vector].
This
binaryRep <= to_stdlogicvector(x"FC");
wouldn't work anyway because the equivalent bit string to x"FC" has a length of 8, while binaryRep has a length of 40 and you don't specify the length std_logic_vector to produce. (And x"FC" already get's converted to an equivalent bit map).
The only to_stdlogicvector function declarations I found are in package fixed_generic_pkg and aren't appropriate.
you could:
binaryRep <= x"00000000FC";
Which matches the bit string length.
Or by including package numeric_std in a use clause:
binaryRep <= std_logic_vector(to_unsigned(16#70F070#,binaryRep'length));
Which converts a natural (an integer subtype) to an unsigned which is then type converted to std_logic_vector with the length derived from binaryRep.
Or using Mentor's std_logic_arith package
binaryRep <= to_std_logicvector(16#70F070#,binaryRep'length);
Which takes an integer argument and a natural length and converts the result to a std_logic_vector.
Or using Synopsys's std_logic_arith package
binaryRep <= conv_std_logic_vector(16#70F070#,binaryRep'length);
Where both arguments are type integer.
(And there are a couple more ways, dependent on VHDL-2008 support).
According to:
https://www.altera.com/support/support-resources/design-examples/design-software/vhdl/v_hex.html
signal A : std_logic_vector(31 downto 0) := x"00000017";
Worked for me :)

What VHDL datatype should I use for a memory address?

I'm developing a description of a BIST engine, and I've been asked by my manager to transition from Verilog to VHDL. I'm very rusty with VHDL, and I can't figure out the right datatype to give to the address register in my code. Most of the time, the address is used to index into arrays.
data : std_logic_vector (2**W-1 downto 0);
...
output = data(addr);
Sometimes though, I need to perform bitwise operations (for example, this code that finds the least-significant 1 in the address):
least_one(0) <= addr(0);
PRIORITY_ENCODER : for i in 1 to (W-1) generate
least_one(i) <= addr(i) and not or_reduce(addr(i-1 downto 0));
end generate PRIORITY_ENCODER;
least_one(W) <= not or_reduce(addr);
Finally, I also rely on the address wrapping around without problem when it overflows (i.e. 1111+1 = 0, and 0-1 = 1111).
So, given all these different uses, what datatype or subtype do I give to the address? When I use integer and the related types, I get errors when I perform the bitwise operations:
ncvhdl_p: *E,APNPFX (filename,17|20): can not make sense of P(...)
When I use std_logic_vector or similiar, I get errors trying to use the address as an array index:
ncvhdl_p: *E,INTYMM (filename,52|17): array index type mismatch [6.4]
I seem to be in a no-win situation here. What data type do I use? Please note, the solution must be synthesizable. Thanks
You want bitwise access and wrapping behaviour:
make addr fundamentally an unsigned vector.
Then you need access to it as an integer:
If you need it as an integer on just one line, use the to_integer call on just that line.
If you need it as an integer in more than one place, create another signal to "shadow" it and put a continuous assignment in the architecture
Like this:
signal addr_int:natural;
....
addr_int <= to_integer(addr);
In this case I would use unsigned type.
This will work very similar to how you are used to std_logic_vector operating in terms of generic bit access, but you can also do arithmetic operations on the address and easily convert to/from integer type, if necessary. Plus it doesn't dirty the sense of std_logic_vector with the "dreaded" std_logic_unsigned package.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
...
architecture myarch of myent is
signal address : unsigned(numbits-1 downto 0);
...
begin
-- as an example
addr_counter : process(sysclk, reset)
begin
if reset = '1' then
address <= (others => '0');
elsif rising_edge(sysclk) then
address <= address + 1;
end if;
end process addr_counter;
...

Resources