Continuous appointment would not seem to work

I am working on a FIR filter, in particular with a delay line. x_delayed initialized to all zeros.

 type slv32_array is array(natural range <>) of std_logic_vector(31 downto 0); ... signal x_delayed : slv32_array(0 to NTAPS-1) := (others => (others => '0')); 

This does not work:

 x_delayed(0) <= x; -- Continuous assignment DELAYS : process(samp_clk) begin if rising_edge(samp_clk) then for i in 1 to NTAPS-1 loop x_delayed(i) <= x_delayed(i-1); end loop; end if; -- rising_edge(samp_clk) end process; 

Simulation


But it does:

 DELAYS : process(samp_clk) begin if rising_edge(samp_clk) then x_delayed(0) <= x; -- Registering input for i in 1 to NTAPS-1 loop x_delayed(i) <= x_delayed(i-1); end loop; end if; -- rising_edge(samp_clk) end process; 

Simulation

The problem with this โ€œsolutionโ€ is that the first element in x_delayed delayed by one pattern, which should not be. (The rest of the code expects x_delayed(0) be the current pattern).

I am using Xilinx ISE 13.2, simulating using ISim, but this was also confirmed by simulating using ModelSim.

What gives?


Edit:

The problem was that although x_delayed(0) did not appear inside the process , it was .

After implementing Brian Drummond's idea, it works great:

 x_delayed(0) <= x; -- Synchronous delay cycles. DELAYS : process(samp_clk) begin -- Disable the clocked driver, allowing the continuous driver above to function correctly. -- https://stackoverflow.com/questions/18247955/#comment26779546_18248941 x_delayed(0) <= (others => 'Z'); if rising_edge(samp_clk) then for i in 1 to NTAPS-1 loop x_delayed(i) <= x_delayed(i-1); end loop; end if; -- rising_edge(samp_clk) end process; 

Simulation


Edit 2:

I accepted OllieB's suggestion to get rid of the for loop. I had to change it, since my x_delayed indexed from (0 to NTAPS-1) , but in the end we get this beautiful process:

 x_delayed(0) <= x; DELAYS : process(samp_clk) begin x_delayed(0) <= (others => 'Z'); if rising_edge(samp_clk) then x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1); end if; -- rising_edge(samp_clk) end process; 

Edit 3:

Following the following OllieB suggestion , it turns out that x_delayed(0) <= (others => 'Z') not needed after its previous change. The following works fine:

 x_delayed(0) <= x; DELAYS : process(samp_clk) begin if rising_edge(samp_clk) then x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1); end if; end process; 
+6
source share
4 answers

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; 
+10
source

During development, drivers are created for all elements in x_delayed, regardless of the loop iterator range. Therefore, x_delayed (0) has two drivers associated with it. Std_Logic and Std_Logic_Vector are reconnected types (i.e., when several drivers are associated with a signal with these types, an enabled function will determine the signal value by looking at the table in the std package. For details, see VHDL coding styles and methodologies for details.

+1
source

the reason you have a problem is because the logic assumes that two things are simultaneously assigned to the same signal - both the continuation and the register assignment cycle. comply with the registry.

change
if you have models, you can use the "trace x" option and see where it came from.
it may be that another simulator also has this function, but for modelsim I'm sure it works

0
source

In the broken example x_delayed (0) <= x;

is equivalent to

 process(x) begin x_delayed(0) <= x; end process; 

Thus, the process assigns x_delayed (0) only when x changes. Since this is a pre-signal, x_delayed (0) will not change immediately, it will change after the delta cycle. Therefore, when the DELAYS process is called an assignment for x_delayed (0), it hasn't happened yet!

Use the variable for x_delayed in your process if you could.

 x_delayed(0) := x; 
0
source

Source: https://habr.com/ru/post/951784/


All Articles