VHDL while loop problem

Status
Not open for further replies.

hitx

Member level 2
Joined
Mar 16, 2007
Messages
49
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,288
Visit site
Activity points
1,723
Hi dear friends,

I have a problem about my codes, but I am not sure whether the problem is about while loop or not. Therefore I need someone help. My code in VHDL is as below :

if rising_edge(q) then
while i <= 3 loop
Xn := 4.0 * Xn * (1.0 - Xn) ;
y := floor (100.0 * Xn);
m <= integer ;
n := m mod 256;
result <= std_logic_vector (to_unsigned(n,8));
i := i + 1;
end loop;
end if;


In here, "q" is a clock signal having 0.75 Hz frequency. And I want to display "result" in 8 bits through leds (0-7) in FPGA board. So loop will iterate 3 times, each iteration I should observe 64,92 and 29 respectively. Now, the clock frequency is 0.75 Hz, I need to observe the numbers. However, I observed only the final value as 29 without observing 64 and 92. So in which part of the codes I missed?

Please help. Thanks.
 

I found the problem - you used a while loop. You cannot use them for synthesis.

It looks like you're a software guy trying to write some VHDL. I suggest you start again by getting out a peice of paper and drawing the circuit you're trying to describe. What you have written cannot be described in hardware, because you used a while loop and you cannot use real types in hardware.
 

Hi TrickyDicky, do not worry about synthesis. Because I used a library contains real, flot and math packages. So the problem is not what you think. By the way, I observe what I should see. If you read me explaination above, you see what a problem I had. The problem is why I observed the last result (29). I also want to see the first and second (64,92) results. But unfortunately not.
 

You appear to want:
Code:
p_label : process is
begin
  while i <= 3 loop
    Xn := 4.0 * Xn * (1.0 - Xn) ;
    y := floor (100.0 * Xn);
    m <= integer (y);
    n := m mod 256;
    result <= std_logic_vector (to_unsigned(n,8));
    i := i + 1;
    wait for rising_edge(clk);
  end loop;
  wait;
end process;

This is almost certainly not synthesizable with existing tools, but might be useful for simulation purposes.

I will say that if you are wanting this to work as you describe -- LEDs on an FPGA board -- you'll have a difficult battle trying to use your method. For this first project, I suggest:
1.) learn the difference between variable (blocking) assign and signal (nonblocking) assign. If you don't know the difference you will almost certainly run into issues.
2.) for the first project, write the full two-process style -- one process that generates the "next state" logic, and one process that registers this logic for the transition to "current state". Most people end up writing HDL in a single-process style (next-state logic inferred by expressions in the clocked process), but effective code can easily be translated between the two representations. If your code can't be translated to a next-state/current-state representation, then you are probably going to have issues in implementation.
3.) "real" types probably aren't supported for synthesis. XST doesn't support them for synthesis, but they can be used to compute constants. You may need to learn more about fixed point (or integer) representations. eg floor(0.75*y + 0.25*x) can be expressed as the msbs of (3*y + x). VHDL has an interesting quirk in that -(A/B) = (-A/B), which is different that C++, where division by 2 implies an arithmetic shift right. XST supports division by powers of two, but I'm not sure if they retain the round-to-zero or use the expected round-to-neg-infinity (floor).
 


I dont think you quite understand the fundamentals of logic and how this code will work. You have said you dont care about synthesis (but you mention LEDs ) so this is purely a language behaviour answer. Remeber this code WILL NOT work on a real board with real LEDs.

Remember, that the process executes in 0 time. So when you get a rising edge on Q, the process completes in 0 time. So m calculates a value based on the old values of Xn and y, and result gets a result based on the old value of m from the last clock cycle. This is the difference between variables and signals. Variables are updated immediatly, and signals are only assigned when the process suspends.

So consider the following code:

Code:
variable a : integer := 0;
signal b : integer := 0;

process(clk)
begin
  if rising_edge(clk) then
    
    for i in 1 to 10 loop
      a := a + 1;
      b <= b + 1;
    end loop;


    output1 <= a;
    output2 <= b;

  end if;
end process;

In this example, Output1 will be 10 after the first clock, but output2 will only be 1. And it will follow this output pattern on each clock:

output1 : 10 20 30 40 50
output2 : 1 2 3 4 5

Because b is only updated when the process suspends, in every loop iteration b is 0 on the first clock, and is assigned the last thing given to it, in this case b <= 0 + 1; Because a is updated immediately, it stores the interim results as it goes.
 

I have very confused my friend. Look this code below (I have tested in my board) :


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity main_var_sig is
port (
mclk : in std_logic;
output1 : out integer range 0 to 255
);


end main_var_sig;

architecture Behavioral of main_var_sig is
begin


process (mclk)
variable xn : integer;
variable i : natural;
begin
xn := 0;
i := 1;
if rising_edge(mclk) then

while i <= 10 loop
xn := xn + 1 ;
output1 <= integer (xn);

i := i + 1;

end loop;

end if;
end process;

end Behavioral;



Then I observed through the led (0-7) on FPGA board, result is output1=10. Now, according to your suggestion, output can not be 10. I used xn as a variable. By the way, what exactly did you mean by saying real board, real LED?? So, my FPGA board is not real!!!!

Thanks
 

Your origional code used real types, and so cannot be used on a board.

For your new code, this works because the output is always 10, as you observed, so there is no problem with the while loop, as the output is always 10, and the synthesisor just connects the output to a constant value of 10. While loops are ok where constants can be evaluated (going a little against what I said) but if there is any variability in the input/output of a while loop, it will not synthesise.

- - - Updated - - -

It is constant 10 because i reaches 10 and is never reset, so Xn gets stuck at 10. You would see the same result in simulation. Using the for loop, the i value is reset to 1 every time the loop restarts.
 

OK. And I used the same codes using signal instead of a variable, and also changes main clock (mclk) to 0.75 Hz, now I can see the numbers such as 1,2,3,4,....,10 on LEDS. Therefore, variable reaches final value suddenly, however signal changes its value every clock cycle. I also observed from the simulation. So if I use signal instead of a variable, and want to see all values in any iteration with a small clock frequency, I can observe results. Now Am I right?

Thanks
 

I highly suggest you read up on digital logic design and VHDL behaviour. As a beginner, you should avoid variables altogether.
You really should step away from the VHDL and get out a peice of paper. Draw the circuit you intend to describe.

VHDL is a Hardware Description Language, not a programming language. If you dont know what the hardware is, how do you expect to describe it. There a many things you could easily do with VHDL that will not map to a digital circuit.
 


The reason you only see the last result is because there is no 'wait' statement in your loop and the process has no way to suspend to allow the signal to update. Until the process exits or until you hit a wait statement the code will execute in zero time which means that any signals will only get updated with the last value that they were assigned. If you single step through the code, you will see the variable (i.e. Xn, y, n and i) all get updated because that's the way that variables are defined to work in VHDL. However, when you hit the signal assignments (i.e. m and result) all that happens is that the assignment get scheduled to occur at the next time the process suspends, the signal will not actually change values until that time since that is how the VHDL language defines signal assignments to operate. Scheduled signal assignments can be overridden in which case the earlier scheduled assignments are then lost.

You can see this behavior in Modelsim by single stepping through the code and then using the drivers statement at the Modelsim command line. For example, stop just before the assignment to 'm' and type 'drivers m' at the command line. What you'll see displayed is that the process is driving 'm' and it currently is driven to some value (say 0). Now step through the code to allow the 'm <= integer ;' statement to be executed and then type 'drivers m'. Assume for now that the result of this assignment is that 'm' should be assigned the value '3'. Now type 'drivers m' and what Modelsim will report is that 'm' is currently still set to 0, but it is scheduled to be updated to a value of '3'. Now repeat this as you iterate through the loop. What you'll see is that the value for 'm' will always be 0, but the scheduled value will change to whatever the next value of 'to_integer' happens to evaluate to.

If you want to see 'm' actually change to the value that you assigned and see it show up in the waveform window then add a 'wait for 0 ns' statement after each signal assignment. The wait statement suspends the process which then allows the signal to be updated. Your process will loop three times and it will still take 0 time to perform those loops but those signals will change to the new assigned values for what is called a 'delta cycle'. A 'delta cycle' can be thought of as an infitesimally small increment of time. The following example process will execute in 0 ns and 3 delta cycles.

Code:
process
begin
   wait until rising_edge(q);
   for i in 1 to 3 loop
      a <= i;
      wait for 0 ns;
   end loop;
   wait; -- Wait forever...this is an example after all
end process;

Note that you can't use a wait statement in a process with a sensitivity list. You didn't show your entire process so I don't know if you had one or not. Your process should start off looking like this..

Code:
process
begin
   wait until rising_edge(q);
   ...The rest of your code
end process;

Your original post says "And I want to display "result" in 8 bits through leds (0-7) in FPGA board" and yet later you say you don't care about synthesis...those two statements are contradictory. If you synthesize the code that you show, the synthesis tool will unroll the loops, note that there are three assignments to those two signals in the loop and ignore the first two because that is exactly the way the VHDL language defines the operation of signal assignments. The ability to see the delta cycle changes is purely a simulation thing. Adding the 'wait for 0 ns' statement also is simply a simulation thing. The synthesis tool will error out on you.

Kevin Jennings
 
Last edited:

the loop with a signal assign will do:
Code:
-- assume y =0 at the start of the process
x:= 0;
y <= 100;
while x < 4 loop
  y <= y + 1;
  x := x + 1;
end loop;
the process then does the following:
x = 0
next_y = 100
next_y = y + 1 = 0 + 1 = 1
x = x+1 = 0+1 = 1
next_y = y + 1 = 0 + 1 = 1
x = x+1 = 1+1 = 2
next_y = y + 1 = 0 + 1 = 1
x = x+1 = 2+1 = 3
next_y = y + 1 = 0 + 1 = 1
x= x+1 = 3+1 = 4
(end of all processes)
y = next_y = 1

thus, after the clock edge y will be set to 1.

what you really want is for the loop index to be a signal, and to remove the loop.
 

Thanks a lot for your great help.,Now I understand the difference between signal type and variable. There are lots of question to ask about my project. I will try to solve these problems myself with hard study and lots of researches, If I am failed, I will turn on you again dear friends.

Take care..
 
Last edited:

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…