Since I started this thread I would like to wrap up.
Until now, when I wanted to make a logic entity which includes complex combinational process between two register stages - plus having the flexibility to export some of the combinational logic to other processes - I had to create many combinational processes inside an entity which use the same signals together with the clocked processes. This created the following problems:
- Difficult readability of the file due to the existence of many processes making it difficult to easily see how they interconnect.
- Signal declaration flooding. Many signals that were used to interconnect combinational code with its respective clocked processes were unnecessarily declared on the top of the file rather than inside the process when they were only there used.
- More writing effort due to writing repeated code (naming processes, using the same keywords, etc)
- Unmodularity of the code. If i wanted to change a small detail in the code I should change it in more places than if the logic entity was inside one process.
So I created an example that successfully uses variables (both combinational and registered, depends on where you assign it and where you read it) in only one process, representing a "complex" logic function with many register stages and combinational code and also having the flexibility to export any stage of the combinational code as asynchronous and not registered (if chosen could be also exported as registered).
So in order to implement the following function:
https://www.alteraforum.com/forum/attachment.php?attachmentid=9057 I needed to implement the following code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity exportcombvariable is
port(clock : in STD_LOGIC;
A, B, C, D : in STD_LOGIC;
Y, Y1,Y2,Y3,Y4: out STD_LOGIC
);
end exportcombvariable;
architecture rtl of exportcombvariable is
begin
process(clock,A,B,C)
variable t1 : STD_LOGIC;
variable t2 : STD_LOGIC;
variable t3 : STD_LOGIC;
variable t4 : STD_LOGIC;
variable r_Y1 : STD_LOGIC;
variable r_Y2 : STD_LOGIC;
variable r_Y3 : STD_LOGIC;
variable r_Y4 : STD_LOGIC;
begin
t1 := A AND B;
if(rising_edge(clock)) then
r_Y1 := t1;
end if;
if(rising_edge(clock)) then
r_Y3 := D;
end if;
t2 := t1 AND r_Y1 AND C;
if(rising_edge(clock)) then
r_Y2 := t2;
end if;
t3 := t2 XOR r_Y2;
t4 := t3 AND r_Y3;
if(rising_edge(clock)) then
r_Y4 := t4;
end if;
--Export section
Y1 <= t1;
Y2 <= t2;
Y3 <= t3;
Y4 <= t4;
Y <= r_Y4;
end process;
end rtl;
which produced the following RTL structure:
https://www.alteraforum.com/forum/attachment.php?attachmentid=9058 Which shows that all the internal to the process signals (whether registered or combinational) are declared as variables inside the process and depending on where they are assigned or/and read they infer registers or not. Also there is the flexibility to export whichever part of the diagram whether coombinational or not at the export section. In that section one uses declared (at the top of the file) signals that can be used by other processes.
In this way the entirety of the logic stays inside one process making it easier to read and understand (one could also use only one clocked if(risingedge) block instead of many that I used, but I did that to show the logic continuity of the actions inside the process), variable naming scope also stays inside the process so one could reuse the process and export the same parts of the logic with different signal names,so that makes it modular, and last but not least it is much easier to modify, add or remove logic from the process without having to rewrite a lot of code (keywords or unique) and waste valuable time.
Finally I grasped a big part of the meaning and use of variables in VHDL and I saw not only how useful they are but also how invaluable they can prove to the designer if he is making reusable modular code.
Thanks a lot to kaz, josyb,FvM, and aprado for the contributions.