====== VHDL combinational logic ======
Combinational logic can be described with concurrent signal assignments, conditional signal assignments, with-select statements and processes.
===== Example: AND Function =====
To begin with, let us start with an AND function with 4 inputs with four different code versions.
==== Concurrent Signal Assignment with Boolean expression====
library ieee;
use ieee.std_logic_1164.all;
entity and_gate is
port(
a_i : in std_ulogic_vector(3 downto 0);
y_o : out std_ulogic);
end and_gate;
architecture rtl of and_gate is
begin
y_o <= a_i(3) and a_i(2) and a_i(1) and a_i(0);
end architecture rtl;
==== Conditional Signal Assignment ====
architecture rtl of and_gate is
begin
y_o <= '1' when a_i = "1111" else '0';
end architecture rtl;
==== With-Select Statement ====
architecture rtl of and_gate is
begin
with a_i select
y_o <= '1' when "1111",
'0' when others;
end architecture rtl;
==== Process ====
This is a process with a "sensitivity list" which contains "a_i". When a_i changes, then the process is evaluated and processes the statements in a sequential manner as in a standard programming language. The last assignment for y_o that is hit in the code flow defines the value that is assigned to y_o. y_o does not change the value during the execution of the process. The value is only changed at the end of the process. Note that this "sequential processing" does not mean that something is processed in several steps in time. The result of this hardware description will still be an AND gate.
architecture rtl of and_gate is
begin
and_p : process(a_i)
begin process
y_o <= '0';
if a_i = "1111" then
y_o <= '1';
end if;
end process;
end architecture rtl;
===== Concurrent Signal Assignments =====
==== Expression evaluation ====
Concurrent signal assignments evaluate the expression on the right side of "<=". The value after the evaluation of the expression is then assigned to the target signal or output port.
target <= EXPRESSION(signals, input ports);
If the target signal or output port is of type std_ulogic or std_ulogic_vector, the expression can be made with the operators which are defined in the [[dt-vhdl-std-library|IEEE std_logic_1164 package]]. That is and, nand, or, nor, xor, xnor, not. The operators are defined for std_ulogic and std_ulogic_vector type signals and ports.
Literals are also expressions, i.e. you can assign '0' or '1' to a target of type std_ulogic. You can assign "1100" to a std_ulogic_vector of length 4.
Example:
architecture rtl of some_circuit is
signal a,b,c : std_ulogic;
signal d,e : std_ulogic_vector(2 downto 0);
begin
d <= e;
e <= "000";
a <= b or c;
end architecture rtl;
===== Conditional Signal Assignments =====
The syntax of a conditional signal assignment is
target <= EXPR1 when COND1 else EXPR2 when COND2 ... else EXPRn;
The expressions can be boolean expressions. The conditions can be comparisons. For std_ulogic and std_ulogic_vector the following comparsion operators can check equality or inequality.
^Operator ^Description ^
|= |Equal ^
|/= |Not Equal ^
Also the logical operators like "and" or "or" can be used for the conditions.
Example:
architecture rtl of some_circuit is
signal y : std_ulogic_vector(3 downto 0);
signal a,b : std_ulogic_vector(1 downto 0);
signal b : std_ulogic;
begin
y <= "1111" when (a = "11" or b = "01") else
"0110" when b = '1' else
"1011" when a /= b else
"0010";
end architecture rtl;
===== With-Select Statement =====
The syntax for a with-select statement is
architecture rtl of some_circuit is
begin
with SELECTOR select
TARGET <= VALUE1 when CHOICEA [| CHOICE B...],
VALUE2 when CHOICEV,
VALUE3 when CHOICEK,
...
[VALUE4 when others];
end architecture rtl;
Example:
architecture rtl of some_circuit is
signal sel : std_ulogic_vector(3 downto 0);
signal y : std_ulogic_vector(1 downto 0);
begin
with sel select
y <= "00" when "0001" | "0010" | "0100",
"01" when "0000",
"10" when others;
end architecture rtl;
===== Process for Combinational Circuit =====
Processes for combinational circuits can also use variables. The assignment operator for a variable assignment is ":=". Variables change the value immediately, but the variable only has a scope inside the process. Inside a process the sequential statements like "if..then..else if..else..end if" or "case" or "for" can be used.
The following example code shows the use of a process with a for loop and and if statement to compute the majority function. m is '1' when more than half of the bits of "a" are '1'. Otherwise m is '0'.
architecture rtl of majority_circuit is
signal a : std_ulogic_vector(7 downto 0);
signal m : std_ulogic;
begin
maj_p : process(a)
variable cnt : integer range 0 to 8;
begin process
m <= '0';
cnt := 0;
for i in 0 to 7 loop
if a(i) = '1' then
cnt := cnt + 1;
end if;
end loop;
if cnt > 4 then
m <= '1';
end if;
end process;
end architecture rtl;
===== Multiple Drivers not allowed =====
Output ports or signals of type std_ulogic or std_ulogic_vector can not have multiple drivers. The following code will not work, because there are two drivers for y_o which is of type "std_ulogic".
architecture rtl of and_gate is
begin
y_o <= a_i(3) and a_i(2) and a_i(1) and a_i(0);
y_o <= '1' when a_i(2) = '0' else '0';
end architecture rtl;
===== Combinational Circuits - Always assign a value =====
Combinational circuits must always have an assignment of a value when a statement is evaluated. Otherwise the synthesis software will infer an unwanted memory element. That is usually a latch. You must make sure that vhdl code that is supposed to describe combinational logic always assigns a value.
The following code will assign the value of "b" to "y" only when "a" has the value '1'. What should happen when a is '0'? The synthesis will infer a latch to remember the last value when "a" is going from '1' to '0'. This is really bad and will result in timing problems.
architecture rtl of crap_code is
signal a,b,y : std_ulogic;
begin
y <= b when a = '1';
end architecture rtl;