One Part or Two Part Process Blocks in HDL - Page 1
Forum section: electronics / general

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: August 02, 2016, 10:43:02 pm
content: I've read a number of articles, papers, and books on HDL design in Verilog and VHDL for FPGAs and there seems to be two camps.One camp advocates putting all of the sequential and combinational logic in a single always or process block. The other camp advocates splitting the sequential logic and the combinational logic into two separate blocks. The two block technique always seems clunky to me because you wind up with a sequential blocks like this:Code:process(clk)beginif rising_edge(clk) thenstate_reg <= state_next;c_reg <= c_next;i_reg <= i_next;err_reg <= err_next;end if;end process;What do you guys do? Single or split process blocks?

author: hamster_nz
author_rank: Super Contributor
timestamp: August 03, 2016, 12:11:53 am
content: If you were asking for advice, I would offer:Start with a two-process design. An unclocked process that computes the new state, and a second is a small clocked assigns the newly calculated state to the current one, and possibly implements an async reset. Using records in VHDL helps keep the code small.Code:-- Process two, when the clock rises assign the next stateprocess(n,clk)begin-- When the clock rises, update the registersif rising_edge(clk) thenr <= n; -- 'r' and 'n' are recordsend if;end process;end Behavioral;Once your brain get a clear concept of "during the cycle the new state is calculated, during the clock edge it is updated", and "all signal assignments are delayed until a process terminates" but once you have these concepts it becomes superfluous and onerous.However, if you have a project where consistency of implementation is important, then it is a great way to standardize how things are done - it adds a lot of rigor to the code and exposes a lot of things that are usually hidden in the subtleties of the code.

author: Someone
author_rank: Super Contributor
timestamp: August 03, 2016, 12:15:16 am
content: Generally you stick with what is most readable, the names of the signals are probably more important than using either of the two styles. Also note that styles should never be strict, it can be more clear to write most of the code inside a single rising edge process but some intermediate steps that need to be explicitly shared between multiple destinations would be described combinatorially outside the main flow.As with most discussions of style you'll get a range of opposed views, so its best to stick with either 1) how the existing code you use is styled, or 2) what feels right for you

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: August 03, 2016, 12:25:25 am
content: Quote from: hamster_nz on August 03, 2016, 12:11:53 amDo you have an example you can share of a good way to do it in a single process?

author: hamster_nz
author_rank: Super Contributor
timestamp: August 03, 2016, 12:51:47 am
content: Quote from: Sal Ammoniac on August 03, 2016, 12:25:25 amHere's a two process design that generate some video signals - you should be able to see that the code is pretty much the same, just that a lot of the cruft and framework has been discarded.Code:library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;entity ColourTest isPort ( clk : in STD_LOGIC;Red : out STD_LOGIC_VECTOR (3 downto 0);Green : out STD_LOGIC_VECTOR (3 downto 0);Blue : out STD_LOGIC_VECTOR (3 downto 0);hSync : out STD_LOGIC;vSync : out STD_LOGIC);end ColourTest;architecture Behavioral of ColourTest istype reg is recordhCounter : std_logic_vector(10 downto 0);vCounter : std_logic_vector(9 downto 0);red : std_logic_vector(3 downto 0);green : std_logic_vector(3 downto 0);blue : std_logic_vector(3 downto 0);hSync : std_logic;vSync : std_logic;end record;signal r : reg := ((others=>'0'), (others=>'0'),(others=>'0'), (others=>'0'), (others=>'0'),'0', '0');signal n : reg;component clk40port(CLK_IN1 : in std_logic;Clk40 : out std_logic);end component;signal pixelClock : std_logic;-- Timing constantsconstant hRez : natural := 800;constant vRez : natural := 600;constant hMaxCount : natural := 1056;constant hStartSync : natural := 840;constant hEndSync : natural := 968;constant vMaxCount : natural := 628;constant vStartSync : natural := 601;constant vEndSync : natural := 605;begin-- Assign the outputshSync <= r.hSync;vSync <= r.vSync;Red <= r.red;Green <= r.green;Blue <= r.blue;clockgen : clk40port map(CLK_IN1 => clk,Clk40 => pixelClock);combi_proc: process(r)beginn <= r;n.hSync <= '0';n.vSync <= '0';-- Count the lines and rowsif r.hCounter = hMaxCount-1 thenn.hCounter <= (others => '0');if r.vCounter = vMaxCount-1 thenn.vCounter <= (others => '0');elsen.vCounter <= r.vCounter+1;end if;elsen.hCounter <= r.hCounter+1;end if;if r.hCounter < hRez and r.vCounter < vRez thenn.red <= r.hCounter(4 downto 1);n.green <= r.hCounter(8 downto 5);n.blue <= r.vCounter(8 downto 5);elsen.red <= (others => '0');n.green <= (others => '0');n.blue <= (others => '0');end if;-- Are we in the hSync pulse?if r.hCounter >= hStartSync and r.hCounter < hEndSync thenn.hSync <= '1'; -- Positive hSync pulseend if;-- Are we in the vSync pulse?if r.vCounter >= vStartSync and r.vCounter < vEndSync thenn.vSync <= '1'; -- Positive vSync pulseend if;end process;clock_proc: process(pixelClock,n)beginif rising_edge(pixelClock)thenr <= n;end if;end process;end Behavioral;Not tested code, but illustrates the difference in code size.Code:library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;entity ColourTest isPort ( clk : in STD_LOGIC;Red : out STD_LOGIC_VECTOR (3 downto 0);Green : out STD_LOGIC_VECTOR (3 downto 0);Blue : out STD_LOGIC_VECTOR (3 downto 0);hSync : out STD_LOGIC;vSync : out STD_LOGIC);end ColourTest;architecture Behavioral of ColourTest issignal hCounter : std_logic_vector(10 downto 0) := (others=>'0');signal vCounter : std_logic_vector(9 downto 0) := (others=>'0');component clk40port(CLK_IN1 : in std_logic;Clk40 : out std_logic);end component;signal pixelClock : std_logic;-- Timing constantsconstant hRez : natural := 800;constant vRez : natural := 600;constant hMaxCount : natural := 1056;constant hStartSync : natural := 840;constant hEndSync : natural := 968;constant vMaxCount : natural := 628;constant vStartSync : natural := 601;constant vEndSync : natural := 605;beginclockgen : clk40port map(CLK_IN1 => clk,Clk40 => pixelClock);clk_proc: process(pixelClock)beginif rising_edge(pixelClock)thenhSync <= '0';vSync <= '0';-- Count the lines and rowsif hCounter = hMaxCount-1 thenhCounter <= (others => '0');if vCounter = vMaxCount-1 thenvCounter <= (others => '0');elsevCounter <= vCounter+1;end if;elsehCounter <= hCounter+1;end if;if hCounter < hRez and vCounter < vRez thenred <= hCounter(4 downto 1);green <= hCounter(8 downto 5);blue <= vCounter(8 downto 5);elsered <= (others => '0');green <= (others => '0');blue <= (others => '0');end if;-- Are we in the hSync pulse?if hCounter >= hStartSync and hCounter < hEndSync thenhSync <= '1'; -- Positive hSync pulseend if;-- Are we in the vSync pulse?if vCounter >= vStartSync and vCounter < vEndSync thenvSync <= '1'; -- Positive vSync pulseend if;end if;end process;end Behavioral;

author: tggzzz
author_rank: Super Contributor
timestamp: August 03, 2016, 06:43:29 am
content: Quote from: Sal Ammoniac on August 02, 2016, 10:43:02 pmI'll echo hamster_nz's commentshttps://www.eevblog.com/forum/microcontrollers/one-part-or-two-part-process-blocks-in-hdl/msg996426/#msg996426I'll add that you should consider how easy it is tomodifya state machine. IMNSHO splitting the sync and combinatorial sections makes it much easier to see which line of code needs to be modified. Multiple nested if-then-elses are easy toinitiallycode, but rapidly become an incomprehensible mess. (The worst cases I've seen were nested 10 deep, shudder).