Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
13 years ago

Newb question- If statements

Im new to programming in VHDL and I seem to be having some difficulty with a particular set of if statements. I understand how conditional statements work, but for whatever reason Im not getting the output I expect. The output never appears to hit the 2nd elsif statement. Ive tried a combination of else-ifs, ifs, and if-else staements to get the result I expect : from 0 to 27000000 clkout goes high, 27000000 to 54000000 clkout goes low, 54000000 to 81000000 goes high, 81000000 goes low and cnt finishes. Here is the snippet of code:

PROCESS(clk,sel,en)

VARIABLE cnt: INTEGER RANGE 0 to 81000000;

BEGIN

IF(en='1') THEN

reset <= '0';

IF(clk' EVENT and clk = '1') THEN

IF(cnt = 81000000)THEN

clkout <= '0';

ELSIF(cnt = 27000000)THEN

clkout <= '0';

ELSIF(cnt = 54000000)THEN

clkout <= '1';

ELSE

cnt:=cnt+1;

clkout <= '1';

END IF;

END IF;

ELSE

clkout <='0';

reset <='1';

cnt:= 0;

sel <= "00";

END IF;

END PROCESS;

10 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    you may try something like:

    process(rst, clk)

    begin

    if ( rsr = '0' ) then

    cnt_reg <= ( others => '0' );

    elsif ( clk'event and clk = '1' ) then

    cnt_reg <= cnt_next;

    end if;

    end process;

    cnt_next <= cnt_reg + 1 when ( cnt_reg < 81000000 ) else

    ( others => '0' );

    process(cnt_reg)

    begin

    IF(cnt_reg = 81000000)THEN

    clkout <= '0';

    ELSIF(cnt_reg = 27000000)THEN

    clkout <= '0';

    ELSIF(cnt_reg = 54000000)THEN

    clkout <= '1';

    ELSE

    clkout <= '1';

    END IF;

    end process;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    No. I prefer signal, no variables, but isn't the problem. You're describing hardware with VHDL. To store a value, like a counter does, you need a register:

    if ( rsr = '0' ) then

    cnt_reg <= ( others => '0' );

    elsif ( clk'event and clk = '1' ) then

    cnt_reg <= cnt_next;

    end if;

    end process;

    this is the sequential part of the circuit. The future value stored in the register is generated by a combinational circuit:

    cnt_next <= cnt_reg + 1 when ( cnt_reg < 81000000 ) else

    ( others => '0' );

    Idem with the output:

    process(cnt_reg)

    begin

    IF(cnt_reg = 81000000)THEN

    clkout <= '0';

    ELSIF(cnt_reg = 27000000)THEN

    ....

    In your code you mixed sequential and combinational circuits. For good coding practices I suggest the book "RTL Hardware design with VHDL". The author is professor Pong Chu.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I prefer to code in parallel with algorithm:

    
    if count = 81000000 then
        count := 0;
    else
       count :=count + 1;
    end if;
    case count is
    when 0 to 27000000 | 54000000 to 81000000=>    clk <= '1';
    when others =>  clk <= '0';
    

    That way you can instantly visualise your code
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks Bertulus and Kaz... I see what you're saying about the combinational versus sequential logic... I totally overlooked that. Kaz I like how you suggested about parallel programming. Mucho gracias!

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Is this because a variable in VHDL cant store a value?

    --- Quote End ---

    Just so you're clear on this: Variables can store a value, and they can be used to describe a register. Remember, variables are updated immediatly and signals are updated when a process suspends. But its down to where you place the code:

    
    --inside clocked process
    count := count + 1;
    if count >= 100 then
    
    This will make count a combinitorial value, and may not store a value depending on the way its used because it is checked AFTER it has been updated.

    But this will infer a register for count:

    
    --inside clocked process
    if count >= 100 then
    ...
    count := count + 1;
    
    Here the count value is checked before it is updated, hence the synthesisor will infer a register.

    So the recommendation is you use signals until you know what you're doing with variables. Some people dont like using variables for registers because they dont use them alot and are used to the standard code structure using signals. Personally, I like to keep things in as local scope as possible, so if I have a pipeline thats only accessed in the same process, you can often do it with local variables rather than global signals.

    On another note - I highly recommend you DONT generate a clock like this. Logic clocks are difficult to time, can cause glitches and are highly affected by temperature variations. I would suggest using clock enables instead.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Tricky, thanks for clarification. I was very confused but how you explained it makes sense now.

    Regarding the clock, my professor showed us this technique to use for clock generation. On the DE2 board Im using, he assigns the external 27mhz pin to the input 'clk' and then uses the integer 'cnt ' to create a 'clkout' that toggles between high and low based on the clk frequency mentioned before . I thought this method seemed a little overkill. You mentioned using a clk enable... are their pre existing functions that allow the user to take advantage of the internal or external clk source?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    there are no pre-existing functions, because thats for you to generate and determine. Clock enables are more reliable because there is no worry about timing or temperature changes:

    
    process(clk)
    begin
      if rising_edge(clk) then 
        if cnt = 999 then
          clk_en <= '1';
          cnt <= 0;
        else
          clk_cnt <= '0';
          cnt <= cnt + 1;
        end if;
        if clk_en = '1' then
          --do something every 1000 clocks
        end if;
      end if;
    end process;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Apart from the clock enable versus "generated" clock point, your original code suffers from a rather trivial problem:

    cnt:=cnt+1 is only conditionally executed. So it stops at cnt = 27000000.