VHDL Unable to initialize array of unsigned vectors - multidimensional-array

The lines:
type some_array_type is array (0 to 4, 0 to 4) of unsigned(7 downto 0);
signal some_array : some_array_type := (others=>(others=>'0'));
cause vivado 2018.2 to throw the error:
[Synth 8-1807] character '0' is not in type unresolved_unsigned
for some reason in a VHDL 2008 file. What it the magical syntax to get Vivado to realize that I'm just trying to initialize the array to zeros? I shouldn't have to write a function to do this. I also tried unsigned((others=>(others=>'0')));
The code below can of course be ignored and isn't needed for anything at all. It is just there for the OCD people. "You have to always include a minimal working example!"
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity some_entity is
port (
clk, rst: in std_logic ;
);
end some_entity ;
architecture arch of some_entity is
type some_array_type is array (0 to 4, 0 to 4) of unsigned(7 downto 0);
-- throws error
signal some_array : some_array_type := (others=>(others=>'0'));
type some_other_array_type is array (natural range <>) of std_logic_vector(7 downto 0);
-- doesn't throw error
signal some_other_array : some_other_array_type(0 to 4) := (others=>(others=>'0'));
begin
-- some made up process
process(clk, rst)
begin
if(rising_edge(clk)) then
if rst = '1' then
some_array <= (others=>(others=>'0'));
else
some_array <= (others=>(others=>'1'));
end if;
end if;
end process;
end arch;

Related

How can I test all cases of vector multiplexer in VHDL?

This is my first VHDL code, I have this multiplexer (two inputs, one selection bit) which has 8bit-vector inputs. How can I write a testing function that generates all possible vectors?
library IEEE;
use IEEE.std_logic_1164.all;
entity mux is
port(
in0, in1: in std_logic_vector(7 downto 0);
sel: in std_logic;
out0: out std_logic_vector(7 downto 0);
end mux;
architecture dataflow of mux is
begin
out0<=in1 when sel='1'
else in0;
end dataflow;
This is the testbench at the moment:
library IEEE;
use IEEE.std_logic_1164.all;
entity testbench is --empty
end testbench;
architecture tb of testbench is
-- DuT component
component mux is
port(
in0, in1: in std_logic_vector(7 downto 0);
sel: in std_logic;
out0: out std_logic);
end component;
signal tb_sel: std_logic;
signal tb_in0, tb_in1, tb_out0: std_logic_vector(7 downto 0);
begin
-- Connect DuT
DuT: mux port map(tb_in0, tb_in1, tb_sel, tb_out0);
process
begin
tb_sel <= 0;
tb_in0 <= "00000000";
tb_in1 <= "00000000";
-- TODO: test all possibilities
end process;
end tb;
Something like this can be used:
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity testbench is --empty
end testbench;
architecture tb of testbench is
signal tb_sel: std_logic;
signal tb_in0, tb_in1, tb_out0: std_logic_vector(7 downto 0);
begin
-- Connect DuT
DuT: entity work.mux port map(tb_in0, tb_in1, tb_sel, tb_out0);
process
begin
-- Done: Test all possibilities
for sel in 0 to 1 loop
for in0 in 0 to 2 ** tb_in0'length - 1 loop
for in1 in 0 to 2 ** tb_in1'length - 1 loop
-- Make stimuli
if sel = 0 then
tb_sel <= '0';
else
tb_sel <= '1';
end if;
tb_in0 <= std_logic_vector(to_unsigned(in0, tb_in0'length));
tb_in1 <= std_logic_vector(to_unsigned(in1, tb_in1'length));
-- Wait for output, also to ease viewing in waveforms
wait for 10 ns;
-- Test output
if sel = 0 then
assert tb_out0 = tb_in0 report "Wrong out0 output value for selected in0 input" severity error;
else
assert tb_out0 = tb_in1 report "Wrong out0 output value for selected in1 input" severity error;
end if;
end loop;
end loop;
end loop;
report "OK (not actual failure)" severity FAILURE;
wait;
end process;
end tb;
Note that I have used instantiation by entity for mux, to avoid the component declaration, where there actually was an error in the port list; clearly showing why it is a bad idea to write the same twice ;-)
Also not that I have included the IEEE numeric_std package.
It can surely be improved with respect to testing of X values also, but for a simple module like a mux the testing above will give the required coverage.
For more advanced testing, take a look at OSVVM.

Found '0' definitions of operator "=", cannot determine exact overloaded matching definition for "="

When i want to check syntax in simulation i have this error.
"Line 105: found '0' definitions of operator "=", cannot determine exact overloaded matching definition for "=" "
I tried to add libraries as others said in others similar threads but it didnt help. This is my code, and my libraries used:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use ieee.std_logic_unsigned.all;
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity multiwib is
port(trigger : in std_logic;
reset : in std_logic;
CLK : in std_logic;
led : out std_logic
);
end multiwib;
architecture multiwib_arch of multiwib is
type stany is (stabilny,niestabilny);
signal stan, stan_nast : stany;
signal licztakty : std_logic_vector(25 downto 0);
signal flaga : std_logic;
begin
reg:process(clk,reset)
begin
if(reset='1')then
stan<=stabilny;
elsif(clk'event and clk='1')then
stan<=stan_nast;
end if;
end process reg;
multi:process(clk,trigger)
begin
stan_nast<=stan;
case stan is
when stabilny=>
flaga<='0';
led<='0';
licztakty<=(others=>'0');
if(trigger='1')then
stan<=niestabilny;
led<='1';
end if;
when niestabilny=>
if flaga ='1' then
stan<=stabilny;
else
stan<=niestabilny;
end if;
end case;
end process multi;
licznik:process(clk,reset)
begin
if reset ='1' then
licztakty<=(others=>'0');
elsif(clk'event and clk='1') then
if(stan=niestabilny) then
licztakty<=licztakty+"01";
led<='1';
elsif(stan=niestabilny and licztakty="?10111110101111000010000000?")then
flaga<='1';
elsif(stan=stabilny) then
licztakty<=(others=>'0');
end if;
end if;
end process licznik;
end multiwib_arch;
You have written licztakty="?10111110101111000010000000?" .
licztakty is a std_logic_vector and ? is not a valid std_logic value. valid options are 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'
'?' makes the compile try and compare std_logic_vector to a string, and I assume you havent written a custom '=' function for the compare.

VHDL asynch ripple counter glitch

Here is a design for 4-bit asynchronous ripple counter (using T flip flop however I didn't define a component for Tff and just coded the behavior of circuit regarding T signals).
Following are the questions:
1.) inout ports, I first defined Q as inout (since it's obviously my output and the bits are also used as clk inputs to their following flip flops). Still, when I wanted to simulate my code, the Q output was UUUU which makes sense cause I had to initialize it with the number I wanted my count to begin with. Though I didn't know how to set an inout initial value (I tried Process ... Q <= "0000"; wait; end process but it didn't work)!
2.) In order to solve the above-mentioned problem I changed my inout port to out (Q_out) and defined Q as a signal, this worked BUT...my counter only changed the Q(0) bit and not the others...thus it counts like: 0,1,0,1,0,1,...
3.) I want to debug this code. I tried another style, instead of a 4-bit output I defined 4 1-bit output signals (Q_out1 to Q_out2) in addition to 4 internal signals Q0 to Q1 and this perfectly works
I just want to know why the first style (Q as a 4_bit vector) didn't work out.
thanks in advance for your help.
Here is my code and its test bench:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity four_bit_Asynch_Counter is
Port ( T0,T1,T2,T3 : in STD_LOGIC;
clk : in STD_LOGIC;
Q_out: out STD_LOGIC_VECTOR (3 downto 0));
end four_bit_Asynch_Counter;
architecture Behavioral of four_bit_Asynch_Counter is
signal Q : STD_LOGIC_VECTOR (3 downto 0) := "0000";
begin
Process (clk,Q(0),Q(1),Q(2))
begin
if (falling_edge(clk)) then
if (T0 = '1') then
Q(0) <= not Q(0);
else
Q(0) <= Q(0);
end if;
end if;
if (falling_edge(Q(0))) then
if (T1 = '1') then
Q(1) <= not Q(1);
else
Q(1) <= Q(1);
end if;
end if;
if (falling_edge(Q(1))) then
if (T2 = '1') then
Q(2) <= not Q(2);
else
Q(2) <= Q(2);
end if;
end if;
if (falling_edge(Q(2))) then
if (T3 = '1') then
Q(3) <= not Q(3);
else
Q(3) <= Q(3);
end if;
end if;
Q_out <= Q;
end Process;
end Behavioral;
--------------- Test Bench------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY tb_counter IS
END tb_counter;
ARCHITECTURE behavior OF tb_counter IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT four_bit_Asynch_Counter
PORT(
T0 : IN std_logic;
T1 : IN std_logic;
T2 : IN std_logic;
T3 : IN std_logic;
clk : IN std_logic;
Q_out : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
--Inputs
signal T0 : std_logic := '1';
signal T1 : std_logic := '1';
signal T2 : std_logic := '1';
signal T3 : std_logic := '1';
signal clk : std_logic := '0';
--Outputs
signal Q_out : std_logic_vector(3 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: four_bit_Asynch_Counter PORT MAP (
T0 => T0,
T1 => T1,
T2 => T2,
T3 => T3,
clk => clk,
Q_out => Q_out
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for clk_period*10;
-- insert stimulus here
wait;
end process;
END;
The TL;DR answer is that q(3) doesn't show up in your process sensitivity list.
architecture behavioral of four_bit_asynch_counter is
signal q: std_logic_vector (3 downto 0) := "0000";
begin
process (clk, q(0), q(1), q(2))
begin
if falling_edge(clk) then
if t0 = '1' then
q(0) <= not q(0);
-- else
-- q(0) <= q(0);
end if;
end if;
if falling_edge(q(0)) then
if t1 = '1' then
q(1) <= not q(1);
-- else
-- q(1) <= q(1);
end if;
end if;
if falling_edge(q(1)) then
if t2 = '1' then
q(2) <= not q(2);
-- else
-- q(2) <= q(2);
end if;
end if;
if falling_edge(q(2)) then
if t3 = '1' then
q(3) <= not q(3);
-- else
-- q(3) <= q(3);
end if;
end if;
q_out <= q;
end process;
end architecture behavioral;
For your process sensitivity list you've discovered a feature in how the sensitivity list is constructed from the expression consisting of primaries - clk, q(0), q(1), q(2).
From IEEE Std 1076 -1993, 8.1 Wait statement:
...
The sensitivity set is initially empty. For each primary in the condition of the condition clause, if the primary is
-- A simple name that denotes a signal, add the longest static prefix of the name to the sensitivity set
-- A selected name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set
-- An expanded name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set
-- An indexed name whose prefix denotes a signal, add the longest static prefix of the name to the sensitivity set and apply this rule to all expressions in the indexed name
...
...
This rule is also used to construct the sensitivity sets of the wait statements in the equivalent process statements for concurrent procedure call statements( 9.3 ), concurrent assertion statements ( 9.4 ), and concurrent signal assignment statements ( 9.5 ).
If a signal name that denotes a signal of a composite type appears in a sensitivity list, the effect is as if the name of each scalar subelement of that signal appears in the list.
...
I only included elements of the rule that are of interest here, the first covers the clock the last element shown covers the std_logic_vector elements specified by selected names.
It helps to understand what is meant by the longest static prefix. This explained in -1993 6.1 Names.
The primaries (indexed names) are static names (q(0), q(1), q(2)), every expression that's part of each indexed name is static.
This means the longest static prefix is the indexed name comprising each primary.
And this leaves q(3) dangling in the breeze for the process signal assignment statement:
q_out <= q;
Without sensitivity to q(3) the value of q_out is not updated until the next event in the sensitivity list, which happens to be on clk:
There are two ways to cure this, you could move the q_out assignment outside the process statement, where it becomes a concurrent signal assignment (with an elaborated equivalent process with a sensitivity list set to q), or you can change the sensitivity list in the present process:
process (clk, q)
So that q_out is updated for an event on q(3) (noting the last quoted paragraph in 8.1 above).
This behavior hold true for later revisions of the standard as well.
With the process sensitivity list is fixed:
Your counter behaves properly.
Also note I commented out the redundant else assignments to the q(0), q(1), q(2) and q(3) a signal will hold it's value until assigned and these are sequential (clocked) statements. Also eliminated the redundant parentheses pairs.
When implementing counters in realisable hardware (either ASIC or FPGA) you should never use a ripple counter. By using the flip-flop output as a clock to the next you will have sub-optimal timing, the tools will not be able to accurately validate the setup and hold times and you are not able to take advantage of dedicated clock routing. In general asynchronous design is a bad idea for real implementations.
A true synchronous design will be much better for synthesis and is much easier to infer in the VHDL code.
Examples of Counter implementations
See the above link for both verilog and vhdl examples of counter implementation.

using a VHDL generate statement in a function

I want to use generate statement but in my code I have a case statements which only takes sequential statements.
Then I thought I will use it in a package where I can define a function such that there also I am getting error as : 'Illegal Sequential statement'.
So what can be done. Any suggestions?
Code block:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE work.my_package.all;
-- Entity for ALU component
-- Use this Entity for your C&A project
ENTITY ALU_E IS
PORT(
reset_n : in std_logic;
clk : in std_logic;
OperandA : in std_logic_vector(3 downto 0);
OperandB : in std_logic_vector(3 downto 0);
Operation : in std_logic_vector(2 downto 0);
Start : in std_logic;
Result_Low : out std_logic_vector(3 downto 0);
Result_High : out std_logic_vector(3 downto 0);
Ready : out std_logic;
Errorsig : out std_Logic);
END ALU_E;
architecture Behavioral_ALU of ALU_E is
signal c : std_logic_vector(7 downto 0);
signal carry_internal :std_logic_vector(4 downto 0);
COMPONENT fulladder IS
PORT(
a: IN std_logic;
b: IN std_logic;
cin : IN std_logic;
cout: OUT std_logic;
s: OUT std_logic );
END component fulladder;
begin
adders: for N in 0 to 3 generate
ff1:fulladder
port map
(a => OperandA(N),b => OperandB(N),cin => carry_internal(N),cout => carry_internal(N+1),s => c(N));
end generate adders;
c(4) <= carry_internal(4);
process(clk,reset_n)
begin
if reset_n = '0' then
if (clk'event) then
case Operation is
when "000" => --no operation
NULL;
when "001" => --Rotate left logical operator ?0000?&A by B steps
c <= rotlef (OperandA,OperandB);
when "010" => --Rotate right logical operator ?0000?&A by B steps (result width is 8 bit)
c <= rotrig (OperandA,OperandB);
when "011" => --Bitwise XOR operation
Result_Low <= OperandA xor OperandB;
when "100" => --Sum of A and B
--here i want to use a statement such that i can call the gatelevel --add function
--I have already all functions gatelevel defined when i try to use portmap or ----generate it gives an error illegal sequential statement
when Others =>
NULL;
end case;
end if;
end if;
end process;
end Behavioral_ALU;
There are a couple of misconceptions in the question.
First the title : there is no function in your actual code. What you have done with the for ... generate statement is generate a separate piece of hardware, operating in parallel with the main process. It will always operate, and always drive signal 'c' with the sum, as if you had written c <= a + b; in place of the for ... generate. It's always, continuously working, not a function you can call only when you want to.
Second, that means that both the adder and the clocked process drive c all the time, with different values. This will not go well... in fact you should see "XXXX" on signal c in simulation.
What I think you want to do is create a new signal, called sum for the adder's output, and drive sum, not c, in the for ... generate. Then, in the Case statement, assigning sum to c will accomplish the Add operation.
As far as why you get the error messages you do, a component instantiation statement or generate statement is a concurrent statement, while a case choice or a function body is comprised of sequential statements.
You don't need a function, you need the sum and carry out from the generate statement instantiated four fulladders.
o
Dummy up an entity/architecture pair for fulladder:
library ieee;
use ieee.std_logic_1164.all;
entity fulladder is
port (
a: in std_logic;
b: in std_logic;
cin: in std_logic;
cout: out std_logic;
s: out std_logic
);
end entity;
architecture foo of fulladder is
begin
s <= a xor b xor cin;
cout <= (a and b) or (a and cin) or (b and cin);
end architecture;
Dummy up a non functional my_package:
library ieee;
use ieee.std_logic_1164.all;
package my_package is
function rotlef (a, b: std_logic_vector) return std_logic_vector;
function rotrig (a, b: std_logic_vector) return std_logic_vector;
end package;
package body my_package is
function rotlef (a, b: std_logic_vector) return std_logic_vector is
variable ret_val: std_logic_vector (a'range);
begin
return ret_val;
end function;
function rotrig (a, b: std_logic_vector) return std_logic_vector is
variable ret_val: std_logic_vector (a'range);
begin
return ret_val;
end function;
end package body;
(note the function return value lengths match the left operand length)
Add a new declaration for the output of the generated fulladders:
architecture changed of alu_e is
signal c: std_logic_vector(7 downto 0);
signal carry_internal: std_logic_vector(4 downto 0);
signal s: std_logic_vector(3 downto 0); -- added
Change the generate statement to use the new signal for the sum:
adders:
for n in 0 to 3 generate
ff1:
fulladder
port map (
a => operanda(n),
b => operandb(n),
cin => carry_internal(n),
cout => carry_internal(n+1),
s => s(n) -- was c(n)
);
end generate;
-- c(4) <= carry_internal(4);
(eliminating the assignment to c(4))
And change the sequence of statements for choice "100":
when "100" => --sum of a and b
result_low <= s; -- added
result_high(0) <= carry_internal(4); --(un)signed?
And your design analyzes, elaborates and simulates (while not doing much - no assignments in the process for case others when operation is undriven and all Us, I didn't write a testbench to drive operation or provide it with a default value).
Notice the declaration of c has a length of 8 while the return value of the two functions will match their a input (length 4).
If you were to execute the dummy functions for operations "001" or "010" you'd get a simulation error due to length mismatch on the right hand side. I left this as is with no insight in to whether or not your rotlef or rotrig functions actually return a longer length.
In general you only want an 8 bit result for multiplies. The length of c and how it get's assigned to result_low and result_high aren't apparent (as yet).
It wasn't possible to discern whether you're doing signed or unsigned arithmetic without more detail. Instead of:
result_high(0) <= carry_internal(4); --(un)signed?
A signed sign extension could look like:
result_high <= (others => carry_internal(4)); --sign extended
Note that when you instantiate your multiplier you'd also want to use a new signal declaration for the 8 bit result. Modifying your rotate operations to assign result_low and result_high would allow c to be used for an instantiated multiply, although you might choose to rename it.
Think of the case statement in the process statement as instantiating a multiplexer, and in some cases you happen to be also expressing logic on inputs. The xor or the sign extension or function calls (which are expressions) are examples.
When you have instantiated components providing function you want to connect their output to a multiplexer input.

How to initialize std_logic_vector?

I have this code
--RAM module
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.numeric_std.all;
entity RAM is
generic(
address_length, data_length : integer);
port(
addr : in std_logic_vector(address_length-1 downto 0);
dat : inout std_logic_vector(data_length-1 downto 0);
rd, wr, en : in bit);
end entity RAM;
architecture RAM_impl of RAM is
type mem is array(2**address_length-1 downto 0) of std_logic_vector(data_length-1 downto 0);
begin
process(rd, wr, en)is
variable cont : mem;
begin
if(en = '1')then
if(wr = '1' and rd = '0')then
cont(to_integer(unsigned(addr))) := dat;
end if;
if(rd = '1' and wr = '0')then
dat <= cont(to_integer(unsigned(addr)));
end if;
end if;
end process;
end architecture RAM_impl;
--Test module
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.numeric_std.all;
entity Example4RAM is
end entity Example4RAM;
architecture Tester of Example4RAM is
signal rd, wr, en : bit;
signal str : std_logic_vector(15 downto 0);
signal ext : std_logic_vector(7 downto 0);
begin
module : entity work.RAM(RAM_impl)
generic map(
address_length => 16,
data_length => 8)
port map(str, ext, rd, wr, en);
tt : process is
begin
str <= X"0001";
ext <= "00000000";
rd <= '0'; wr <= '1';
wait for 5 ns;
en <= '1';
wait for 5 ns;
rd <= '0'; wr <= '0';
wait for 10 ns;
rd <= '1'; wr <= '0';
end process;
end architecture Tester;
When i run simulation on this RAM module str vector initializes fine but ext vector stays uninitialized. In RAM module str is in vector and ext is inout vector. Is this somehow making problem and does anyone know the solution? (I did change source since yesterday but it doesn't work still)
I added a RAM module and tinkered with the test stimulus slightly (ext is driven to all 'Z's when wr goes invalid (the behavioral model requires no hold over).
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity RAM is
generic (
constant address_length: natural := 16;
constant data_length: natural := 8
);
port (
signal str: in std_logic_vector (address_length-1 downto 0);
signal ext: inout std_logic_vector (data_length-1 downto 0);
signal rd: in BIT;
signal wr: in BIT
);
end entity;
architecture RAM_impl of RAM is
type ram_array is array (natural range address_length-1 downto 0)
of std_logic_vector (data_length-1 downto 0);
signal mem_array: ram_array;
begin
MEMORY:
process (str, ext, rd, wr)
variable addr: natural range 0 to 2**address_length -1 ;
begin
addr := TO_INTEGER(UNSIGNED(str)); -- heed the warnings
if wr = '1' then
mem_array(addr) <= ext;
end if;
if rd = '0' then
ext <= (others => 'Z');
else
ext <= mem_array(addr);
end if;
end process;
end architecture;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- use IEEE.numeric_std.ALL;
entity Example4RAM is
end entity Example4RAM;
architecture Tester of Example4RAM is
signal rd,wr,clk: bit;
signal str: std_logic_vector(15 downto 0);
signal ext: std_logic_vector(7 downto 0);
begin
module:
entity work.RAM(RAM_impl)
generic map (
address_length=>16,
data_length=>8
)
port map (
str,
ext,
rd,
wr
)
;
tt:
process
begin
str<=X"0001";
ext<="00000000";
wait for 5 ns;
rd<='0';wr<='1';
wait for 5 ns;
rd<='0';wr<='0';
ext <= (others => 'Z'); -- ADDED
wait for 10 ns;
rd<='1';wr<='0';
wait for 20 ns; -- ADDED
str <=X"0002"; -- ADDED
wait for 20 ns; -- ADDED
wait;
end process;
end architecture Tester;
The change to the stimulus includes a change to the RAM address showing that reading an uninitialized location returns 'U's (uu on the waveform):
ghdl -a exampleram.vhdl
ghdl -r Example4RAM --wave=Example4RAM.ghw
../../../../libraries/ieee/numeric_std-body.v93:2098:7:#0ms:(assertion warning):
NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
open *.ghw
Essentially, the process and the RAM drive ext with all 'Z's whenever either one shouldn't be driving a value out. Writing before reading hides the 'U' values from str address X"0001". As you see, if the address is changed to a location that is not initialized, the 'U's show up. Resolution delivers the RAM read data or provides write data to the RAM array on the bidirectional data bus (ext).
(This was done on a Mac with a ghdl mcode version (direct compile, like for Windows, requiring no explicit elaboration), and displayed using GTKWave).
The assertion warning (metavalue detected) comes from the default value assigned to str (all 'U's) at time zero (#0ms).

Resources