FONT SIZE : AAA
If we consider a simple inverter in VHDL, we can develop a single inverter which takes a single input bit, inverts it and applies this to the output bit. This simple VHDL is shown as follows:
library ieee;
use ieee.std_logic_1164.all;
entity inverter is
port (
a : in std_logic;
q : out std_logic
);
end entity inverter;
architecture simple of inverter is
begin
q <= not a;
end architecture simple;
Clearly the inputs and output are defined as single std_logic pins, with direction in and out, respectively. The logic equation is also intuitive and straightforward to implement. We can extend this to be applicable to n bit logic busses by changing the entity (the architecture remains the same) and simply assigning the input and outputs the type std_logic_vector instead of std_logic, as follows:
library ieee;
use ieee.std_logic_1164.all;
entity bus_inverter is
port (
a : in std_logic_vector(15 downto 0);
q : out std_logic_vector(15 downto 0)
);
end entity bus_inverter;
architecture simple of bus_inverter is
begin
q <= not a;
end architecture simple;
As can be seen from the VHDL, we have defined a specific 16-bit bus in this example, and while this is generally fine for processor design with a fixed architecture, sometimes it is useful to have a more general case, with a configurable bus width. In this case we can modify the entity again to make the bus width a parameter of the model, which highlights the power of using generic parameters in VHDL.
library ieee;
use ieee.std_logic_1164.all;
entity n_inverter is
generic (
n : natural := 16
);
port (
a : in std_logic_vector((n−1) downto 0);
q : out std_logic_vector((n−1) downto 0)
);
end entity n_inverter;
architecture simple of n_inverter is
begin
q <= not a;
end architecture simple;
We can of course create separate models of this form to implement multiple logic functions, but we can also create a compact multiple function logic block by using a set of configuration pins to define which function is required. If we define a general logic block that has 2 n-bit inputs (A and B), a control bus (S) and an n-bit output (Q), then by setting the 2-bit control word (S) we can select an appropriate logic function according to the following table:
Clearly we could define more functions, and this would require more bits for the select function (S) which could also be defined using a generic, but this limited set of functions demonstrates the principle involved. We can define a modified entity as shown:
library ieee;
use ieee.std_logic_1164.all;
entity alu_logic is
generic (
n : natural := 16
);
port (
a : in std_logic_vector((n−1) downto 0);
b : in std_logic_vector((n−1) downto 0);
s : in std_logic_vector(1 downto 0);
q : out std_logic_vector((n−1) downto 0)
);
end entity alu_logic;
Now, depending on the value of the input word (S), the appropriate logic function can be selected. We can use the case statement introduced in Chapter 3, A VHDL Primer to define each state of S and which function will be carried out in a very compact form of VHDL:
architecture basic of alu_logic is
begin
case s is
when “00” => q <= not a;
when “01” => q <= a and b;
when “10” => q <= a or b;
when “11” => q <= a xor b;
end case;
end architecture basic;
Clearly this is an efficient and compact method of defining the combinatorial logic for each state of the control word (S), but great care must be taken to assign values for every combination to avoid inadvertent latches being introduced into the logic when synthesized. To avoid this, a synchronous equivalent could also be implemented that only applied the logic function on the clock edge specified.
In this example, all of the possible combinations are specified; however, in order to avoid possible inadvertent latches being introduced, it would be good practice to use a “when others” statement to cover all the unused cases.
The arithmetic heart of an ALU is the addition function (Adder). This starts from a simple 1-bit adder and is then extended to multiple bits, to whatever size addition function is required in the ALU. The basic design of a 1-bit adder is to take two logic inputs (a and b) and produce a sum and carry output according to the following truth table:
Figure 21.1 1-bit adder.
This can be implemented using simple logic with a 2 input AND gate for the carry, and a 2 input XOR gate for the sum function, as shown in Figure 21.1.
This function has a carry out (carry), but no carry in, so to extend this to multiple bit addition, we need to implement a carry in function (cin) and a carry out (cout) as follows:
With an equivalent logic function as shown in Figure 21.2:
This can be implemented using standard VHDL logic functions with bit inputs and outputs as follows. First, define the entity with the input and output ports defined using bit types:
entity full_adder is
port (sum, co : out bit;
a, b, ci : in bit);
end entity full_adder;
Then the architecture can use the standard built-in logic functions in a dataflow type of model, where logic equations are used to define the behavior, without any delays implemented in the model.
Figure 21.2 1-bit adder with carry-in and carry-out.
architecture dataflow of full_adder is
begin
sum <= a xor b xor ci;
co <= (a and b) or
(a and ci) or
(b and ci);
end architecture dataflow;
This model is now a simple building block that we can use to create multiple bit adders structurally by linking a number of these models together.
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Active Active
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Active Active
RoHS:
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Active Active
RoHS:
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Obsolete -
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Obsolete -
RoHS: No RoHS
Support