Programmable Logic/VHDL Module Structure
Module Structure Overview
There are two methods of creating a model: top-down and bottom-up. A model can also be defined to varying levels of detail.
Being a modeling language, VHDL supplies a rich variety of constructs to fit the various methods and level of details used in modeling. Amongst these are: Entities, Architectures, Packages, and Libraries.
Here signals are used for propagating the data through the different stages of the implementation. Sometimes these signals are used to instantiation of the components which we are using in our design. These behave like a road map for propagating the data.
variable variable_name : type; variable variable_name : type := initial_value;
Rules and Examples
variable HEIGHT : integer := 8; variable COND : boolean := true; variable IN_STRING : string(1 to 80); variable M,N : bit := '1'; variable I : integer range 0 to 3;
A variable may be given an explicit initial value when it is declared. If a variable is not given an explicit value, its default value will be the leftmost value (
'left) of its declared type.
variable I : integer range 0 to 3; -- initial value of I is 0 variable X : std_ulogic; -- initial value of X is 'U'
Variables within subprograms (functions and procedures) are initialised each time the subprogram is called:
function PARITY (X : std_ulogic_vector) return std_ulogic is variable TMP : std_ulogic := '0'; begin for J in X'range loop TMP := TMP xor X(J); end loop; --no need to initialise TMP return TMP; end PARITY;
Variables in processes, except for "FOR LOOP" variables, receive their initial values at the start of the simulation time (time = 0 ns)
process (A) variable TMP : std_ulogic := '0'; begin TMP := '0'; -- in this example we need to reset -- TMP to '0' each time the process -- is activated for I in A'low to A'high loop TMP := TMP xor A(I); end loop; ODD <= TMP; end process;
Scalar Data Types
Composite Data Types
An entity is used to describe the interface of the VHDL module to other modules. All signals entering or exiting a vhdl module must be declared in the entity declaration. An example of an entity describing the interface for a two input AND gate can be found below:
ENTITY and2 IS PORT(A : in std_logic; B : in std_logic; F : out std_logic ); END and2;
Inside the entity a port declaration can be found. There are the following kinds of ports:
|in||Specifies a port that can be read from but not written to. A in port cannot be used on the left side of an assignment.|
|out||Specifies a port that can be written to but not read from. A out port can only be used on the left side of an assignment|
|in/out||Specifies a port that can be read and written to. An inout port is commonly used to describe tristate buses.|
|buffer||Specifies a out port whose current value can be read from. The same functionality can be achieved by assigning to an internal signal in the VHDL code, reading from that signal when needed, and assigning the internal signal to the out port using a concurrent statement.|
An architecture in VHDL describes how functionality of the module is implemented. Below is the architecture for a two input and gate:
ARCHITECTURE and2_rtl OF and2 IS -- Signal, component, type and constant declarations go here. ... BEGIN -- Concurrent statements and processes go here F <= A and B; ... END and2_rtl;
Types of Architecture Implementation
An architecture can be implemented in different ways depending on its purpose.
A structural implementation connects and instantiates other modules. It serves to organize and connect modules together. A strict structural implementation contains only other instantiated blocks wired together using port maps.
A behavioral implementation describes how a modules should function using the full array of VHDL constructs available. Behaviorally designed modules are not necessarily synthesizable, but are useful for modeling and testing synthesizable modules.
A register transfer implementation describes the functionality of a module in terms of registers and the transformation of the data that flows between the registers. Register transfer implementations are commonly used to describe modules that are to be synthesized on actual devices.
A VHDL package is used to contain a group of reusable data types, functions, procedures, and other VHDL constructs. The basic syntax for a package is as follows:
PACKAGE package_name IS ... END package_name; PACKAGE BODY package_name IS ... END package_name;
The package header is for the declaration of VHDL constructs. The package body is for their implementation. Not all constructs (such as data types) need an entry in the body. The body is commonly used for function and procedure implementation.
A library establishes a namespace for the modules to exist in. When compiled by a simulator or synthesis tool, every package and entity is compiled into a library. There is no way for a VHDL file to specify which library it is compiled into. This is determined by the tool used to compile the VHDL code. The default library that tools compile VHDL objects into is called work. This means the following statement is assumed when creating VHDL models:
VHDL models can use the library keyword to make libraries visible to a module and use objects from them. This is needed to include packages from other libraries and to directly instantiate entities from other libraries.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
The library keyword makes a library visible to a VHDL design. After the library is made visible, packages inside the library can be used. The next line states to make everything declared in the ieee.std_logic_1164 namespace declared in the current namespace. For example, this allows us to use the statement:
signal sQ: std_logic;
signal sQ: ieee.std_logic_1164.std_logic;
Instantiation of a VHDL Module
There are two ways a VHDL modules can be instantiated. The original way, specified in VHDL '87, uses a component, port map, and corresponding entity declaration. The newer way, specified in VHDL '93, uses just the port map and corresponding entity declaration. Each one is useful under certain circumstances. For each method the following entity will be instantiated:
entity D_FF is port( clk : out std_logic; rst : out std_logic; D : in std_logic; Q : in std_logic ); end entity D_FF; architecture rtl of D_FF is ... begin ... end architecture rtl;
architecture rtl of uses_d_ff is ... component D_FF is port( clk : out std_logic; rst : out std_logic; D : in std_logic; Q : in std_logic ); end component D_FF; ... signal sClk: std_logic; signal sRst: std_logic; signal sD: std_logic; signal sQ: std_logic; ... begin u_D_FF: component D_FF port map( clk => sClk, rst => sRst, D => sD, Q => sQ ); ... end architecture rtl;
Not using a component shortens the syntax quite a bit. To instantiate D_FF above, the following code is used:
architecture rtl of uses_d_ff is ... signal sClk: std_logic; signal sRst: std_logic; signal sD: std_logic; signal sQ: std_logic; ... begin u_D_FF: entity work.D_FF(rtl) port map( clk => sClk, rst => sRst, D => sD, Q => sQ ); ... end architecture rtl;
As long as the tools used support this syntax, not using a component is recommended because it improves code maintainability. When signals are added/removed and removed from entities, they only need to be added or removed from the entity declaration and the port map. Components are useful when what is being instantiated does not have a VHDL module. When instantiating Verilog designs in VHDL or using IP cores, this is sometimes necessary. This allows the VHDL compiler to create a "black box" when compiling the VHDL and connect the actual model to the black box later.
| This page or section is an undeveloped draft or outline.
You can help to develop the work, or you can ask for assistance in the project room.