In the first case, x_delayed(0) actually has two drivers, the process outside is x_delayed(0) <= x , and the process is implicit inside DELAY.
The driver inside the process is a consequence of the standard VHDL concept called the "long static prefix" described in the VHDL-2002 standard (IEEE Std 1076-2002) section "6.1 Names" and the construction of a loop with the loop variable i , with the longest static prefix for x_delayed(i) is x_delayed .
The VHDL standard further describes process drives in the "12.6.1 Drivers" section, which states: "... There is one driver for a given scalar of signal S in the process statement, provided that there is at least one assignment signal in this statement process and that the longest static prefix of the target signal of this signal assignment operator denotes S ... ".
So, as a (possibly unexpected) consequence, x_delayed(0) has a driver in the DELAY process that manages all std_logic elements up to "U" since they are not assigned, as a result of which the std_logic permission function calls the resulting value as "U", regardless from what value the external x_delayed(0) <= x controls.
But in the case of your code, it seems to be more for it, since the output of the simulation for x_delayed(0) really has some "0" values, as can be seen from the figures. However, it is difficult to understand this when I do not have all the code.
One way to see what the loop is causing is to manually loop out by replacing for ... loop with:
x_delayed(1) <= x_delayed(1-1); x_delayed(2) <= x_delayed(2-1); ... x_delayed(NTAPS) <= x_delayed(NTAPS-1);
This, of course, cannot be used for configurable modules with NTAPS as common, but it may be interesting to see that the operation is then equally intuitively expected.
EDIT . Several options are listed in the โeditโ sections after the question above, based on comments. Below is a solution with a variable that allows complex expressions if required. If a complex expression is not required, then according to OllieB's suggestion, you can reduce the purpose of x_delayed(1 to x_delayed_dir'high) <= x_delayed(0 to x_delayed_dir'high-1) :
x_delayed(0) <= x; DELAYS : process(samp_clk) variable x_delayed_v : slv32_array(1 to NTAPS-1); begin if rising_edge(samp_clk) then for i in 1 to NTAPS-1 loop x_delayed_v(i) := x_delayed(i-1); -- More complex operations are also possible end loop; x_delayed(1 to x_delayed_dir'high) <= x_delayed_v; end if; -- rising_edge(samp_clk) end process;