Forum Discussion
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
Honored 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
Honored Contributor
Is this because a variable in VHDL cant store a value?
- Altera_Forum
Honored 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
Honored Contributor
I prefer to code in parallel with algorithm:
That way you can instantly visualise your codeif 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'; - Altera_Forum
Honored 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
Honored 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:
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 count := count + 1; if count >= 100 then
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.--inside clocked process if count >= 100 then ... count := count + 1; - Altera_Forum
Honored 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
Honored 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
Honored Contributor
Okay I see what you're saying.
- Altera_Forum
Honored 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.