What is wrong with my if-else statment in this VHDL code for a counter? [SOLVED] - Page 1
Forum section: electronics / general

author: Dmeads
author_rank: Regular Contributor
timestamp: March 06, 2021, 06:19:33 am
content: Hello all!Been really scratching my head trying to figure out what I am doing wrong here. I am a VHDL beginner so take it easycode errors sayCode:design.vhd:49:12: 'if' is expected instead of 'process'design.vhd:49:11: missing ";" at end of statementdesign.vhd:49:12: 'end' is expected instead of 'process'you can see the edaplayground link for yourself.https://www.edaplayground.com/x/8bqFI really thought I had my end if statments in the right place, but maybe i have been staring at this for too long, a fresh pair of eyes would help.Thanks, here is the code (the error is somewhere in the COUNT_PROC0 near the end of the entity):Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity decade_counter_behavioral isport (i_clk : in std_logic;o_count : out std_logic_vector (3 downto 0));end decade_counter_behavioral;architecture behavioral of decade_counter_behavioral issignal r_count : unsigned (3 downto 0) := "0000"; -- output register for countersignal r_clk_count : unsigned (25 downto 0) := x"0000000"; -- counts clk pulsessignal r_count_en : std_logic := '0'; -- count enablebeginCLK_COUNT_PROC : process (i_clk) -- counts the clk cyclesbeginif rising_edge (i_clk) thenif (r_clk_count < x"3B9ACA0") then -- 62,500,500 or 0.5 sec @ 125 MHZ system clkr_clk_count <= r_clk_count + 1;elser_clk_count <= x"0000000";end if;end if;end process; -- CLK_COUNT_PROCCOUNT_EN_PROC : process (r_clk_count) -- keeps the count enable high for two clk cycles for ff setup/hold timebeginif (r_clk_count > x"3B9AC9E") thenr_count_en <= '1';elser_count_en <= '0';end if;end process; -- COUNT_EN_PROCCOUNT_PROC : process (i_clk, r_count_en) -- only counts up when r_count_en is high (every 0.5 sec)beginif rising_edge (i_clk) thenif (r_count < "1001" and r_count_en = '1') thenr_count <= r_count + 1;else if (r_count = "1001" and r_count_en = '1') thenr_count <= "0000";end if;end if;end process; -- COUNT_PROCo_count <= std_logic_vector(r_count); -- output assignmentsend behavioral;

author: hamster_nz
author_rank: Super Contributor
timestamp: March 06, 2021, 07:31:45 am
content: `else if' opens an other code block/level of indentation.'elsif' is what you want.

author: NorthGuy
author_rank: Super Contributor
timestamp: March 06, 2021, 03:48:51 pm
content: Quote from: Dmeads on March 06, 2021, 06:19:33 amThis is not related to setup/hold time, but will make r_count increment twice in a row.

author: Bassman59
author_rank: Super Contributor
timestamp: March 06, 2021, 06:33:38 pm
content: I'm going to make some general observations on coding style here. The code as originally written is a mish-mash of various styles and is .. meh. So indulge me. Most of my comments are about easily seeing what an "end" closes.Code:library ieee;use ieee.std_logic_1164.all;use ieee.numeric_std.all;entity decade_counter_behavioral isport (i_clk : in std_logic;o_count : out std_logic_vector (3 downto 0));end decade_counter_behavioral;For completeness' sake, VHDL allows the closing "end" of a thing to include both its label and the type of thing, so let's make this entity declaration complete:Code:library ieee;entity decade_counter_behavioral isport (i_clk : in std_logic;o_count : out std_logic_vector (3 downto 0));end entity decade_counter_behavioral;Here is the architecture ...Code:architecture behavioral of decade_counter_behavioral issignal r_count : unsigned (3 downto 0) := "0000"; -- output register for countersignal r_clk_count : unsigned (25 downto 0) := x"0000000"; -- counts clk pulsessignal r_count_en : std_logic := '0'; -- count enableI prefer to use the(others => '0')idiom here. Why? Because when you change the counter width from four bits to eight bits you don't need to change the initializer. This works for std_logic_vector as well as its subtypesunsignedandsigned.Code:architecture behavioral of decade_counter_behavioral issignal r_count : unsigned (3 downto 0) := (others => '0'); -- output register for countersignal r_clk_count : unsigned (25 downto 0) :=(others => '0'); -- counts clk pulsessignal r_count_en : std_logic := '0'; -- count enableNow the main block of the entity.Code:beginCLK_COUNT_PROC : process (i_clk) -- counts the clk cyclesbeginif rising_edge (i_clk) thenif (r_clk_count < x"3B9ACA0") then -- 62,500,500 or 0.5 sec @ 125 MHZ system clkr_clk_count <= r_clk_count + 1;elser_clk_count <= x"0000000";end if;end if;end process; -- CLK_COUNT_PROCFirst, I'd declare a constant for the terminal count and put it in the declarative part of the architecture (between the keywordarchitectureand the firstbegin). Of you could make it a generic on your entity!Second, the decorations. VHDL allows a process declaration to be:Code:label : process (i_clk) isNote the word "is." Using it here makes it consistent with the entity and architecture declarations.Third, there's the line:Code:end process; -- CLK_COUNT_PROCVHDL allows you to use a label as part of an "end" clause -- and you've already written the label in the comment! So fix it:Code:end process CLK_COUNT_PROC;Code:COUNT_EN_PROC : process (r_clk_count) -- keeps the count enable high for two clk cycles for ff setup/hold timebeginif (r_clk_count > x"3B9AC9E") thenr_count_en <= '1';elser_count_en <= '0';end if;end process; -- COUNT_EN_PROCIn addition to my notes about the decorations and the use of constants for terminal counts, you do realize that this is a combinatorial process, right? r_count_en is not a register. Is that what you want?If that's what you want, you can also write this as a continuous assignment:Code:r_count_en <= '1' when r_clk_count > MY_TERMINAL_COUNT else '0';and even simpler in VHDL 2008 (someone please check this!)Code:r_count_en <= r_clk_count > MY_TERMINAL_COUNT;Code:COUNT_PROC : process (i_clk, r_count_en) -- only counts up when r_count_en is high (every 0.5 sec)beginif rising_edge (i_clk) thenif (r_count < "1001" and r_count_en = '1') thenr_count <= r_count + 1;else if (r_count = "1001" and r_count_en = '1') thenr_count <= "0000";end if;end if;end process; -- COUNT_PROCThis is a synchronous process, sensitive only to the clock edge.r_count_endoesn't have to be on the sensitivity list, and in a code review this will get flagged.Code:o_count <= std_logic_vector(r_count); -- output assignmentsDeclare your output count port to be unsigned and you won't need to do the typecast.Code:end behavioral;For completeness' sake this should be:Code:end architecture behavioral;

author: NorthGuy
author_rank: Super Contributor
timestamp: March 06, 2021, 07:19:24 pm
content: Quote from: Bassman59 on March 06, 2021, 06:33:38 pmStyles may be important for some people. I prefer simplicity.What I don't like in this code is the behaviour when the counters overflow. In reality, it doesn't matter what they do in the overflown state because they never overflow. So, there's no need to create a special case for this situation. It's better to let the counter do something which it already does in other situations. This will lead to smaller logic. This also let us get rid of the complex ordered comparison in favour of much simple equality. Like this:Code:process (i_clk) -- counts the clk cyclesbeginif rising_edge (i_clk) thenr_clk_count <= r_clk_count + 1;if r_clk_count = x"3B9ACA0" then -- 62,500,500 or 0.5 sec @ 125 MHZ system clkr_clk_count <= x"0000000";r_count <= r_count + 1;if r_count = "1001" thenr_count <= "0000";end if;end if;end if;end process;Disclamer: Justed typed it in as an illustration. May contain bugs.