Chapter 14

Libraries

Libraries are an important concept in VHDL, and yet they seem to cause a lot of problems and confusion amongst VHDL users. For that reason, this short chapter has been included to give a brief overview of libraries and recommendations on how to organise your work in libraries.

14.1 The Library

A library can be regarded as a container that contains compiled design units. A library can also be regarded as the destination for VHDL compilers.

When a VHDL source file is compiled (or analysed seems to be the preferred term in VHDL circles) into a VHDL system, it is split into separate design units. If a source file contains, say, ten design units then the file will be split into ten parts. Each design unit is then analysed in isolation and the compiled result, an intermediate form, is saved into a library. At the end of the analysis, the library will contain ten design units.

Also, when a simulation is run, a design unit is simulated directly in its library, so the original source file is not involved in the simulation process. Instead, the model is built by assembling all of the intermediate forms for all of the design units in the model into a runnable model.

Typically, a simulator will analyse VHDL source into object code – so object code is the intermediate form. Then, the simulation consists of linking the object code into a program that is then run. However, this is not the only approach possible and some simulators use different techniques.

A simulator and a synthesiser will both use the same basic mechanism, the main difference being that a design unit is synthesised from the library rather than simulated. However, the synthesiser will use a very different intermediate form from the simulator. This means that simulation and synthesis must be carried out separately in different libraries. Once again, the original source file has no part to play in the synthesis process.

This demonstrates that the libraries of each VHDL tool must be kept separate, because each tool will use a different intermediate form to store design units in its libraries. So, for example, the simulator's library ieee will be separate from the synthesiser's library ieee.

The main benefit of libraries to the VHDL user is that it allows a natural way of partitioning a design into its subsystems. Each major subsystem can be designed separately in its own library. This library will contain the subsystem itself plus all the test benches for unit testing of that subsystem. Then, the whole design can be assembled from another library, using the subsystem libraries as resources. This top-level library will contain only references to the other subsystems, not copies, thus ensuring that there is only one definitive copy of each component. The top-level library will also contain the test benches for the overall system tests.

All VHDL systems use this library system because it is part of the VHDL standard. However, the standard says nothing about how the library system should be implemented, it simply states how it should appear in VHDL terms as a purely abstract concept.

In practice, a library is always implemented as a directory that can be placed anywhere on a file system. The directory contains the files that the VHDL system uses to represent the compiled design units. These are generally hidden from the users of the system since there is no need to know anything about what happens in a VHDL library directory. The format of the files are specific to the VHDL system that created them, so a library is not portable between VHDL systems.

14.2 Library Names

Every VHDL library should be given a name. When you refer to a library in VHDL, you refer to it by this name, not its location on the file system. For example, the library ieee has already been referred to in previous chapters. It has appeared many times in the example VHDL source code in the form of a library clause:

library ieee;

The library clause makes all of the design units within the named library available for use in the current design unit. For example, if the library clause appears before an entity, then it means that the entity can use any definitions in that library for defining the ports. It also means that the associated architecture can use the library definitions, since architectures inherit library clauses from their entities.

The library clause is used in conjunction with the use clause. The following combination has been used in many of the examples:

library ieee;

use ieee.std_logic_1164.all;

entity ...

This first makes the library ieee available for use in the following entity and its architecture, then it makes all the definitions from package std_logic_1164 found in that library available for use. This makes std_logic, std_logic_vector and all the associated operators available for use.

This is a typical example: making a resource available for use in a design unit is a two-stage process. First, the library containing the resource is made available, and secondly the resource itself is made available.

Library ieee is a container for IEEE standard VHDL components that are not directly part of the VHDL standard but that have been standardised for use in application areas that use VHDL. The exact contents of library ieee will be discussed in Section 14.4.

The obvious question is, where is library ieee? The VHDL definition says nothing about this, and there is no mechanism in the language itself for specifying where to look for a library, so the question of how the VHDL analyser finds a library is simulator or synthesiser specific. All VHDL systems must have some mechanism for mapping the name of a library onto the directory that contains it. Since this is outside the language definition, the methods used vary enormously, although the most common method involves some sort of mapping file that contains a list of library mappings. Typically there will be one such file for each working directory, so you can have a different set of library mappings for each directory you work in.

When you create a library of your own to work in, you should always give it a name. Most VHDL systems enforce this anyway, so you cannot create a nameless library. It is helpful to use a name that gives some clue as to what its purpose is. For example, a library of utilities could be called utilities, whilst a library containing the parts of a FIR filter could be called fir_filter or even just fir.

There are restrictions on the names that can be used. Since the library name will be referred to from VHDL, the name must obey the rules of VHDL names. This means that it must start with a letter, contain only letters, digits and underscores and not have two consecutive underscores. Finally, it must not be a VHDL keyword or the reserved library name work. For reference, the VHDL keywords are listed in Appendix B.1. The reserved library name work will be explained in the next section.

14.3 Library Work

The reserved library name work is used to refer to the library that you are currently working in. It is an alias or pseudonym for the library, since the library will also have a name of its own. You can think of the name work as a pointer or reference to a library rather than a library itself. All compilations, simulations or syntheses are carried out in library work.

To illustrate the use of libraries, an artificial design will be used. The design will be a two-way communications device consisting of a separate transmitter and receiver. The top level of the design will be the whole communications system that brings together the transmitter and receiver. Finally, such a design will inevitably have common utilities and subcomponents that can be shared between the components.

In this simple example it can be seen that there is a natural division into four libraries. The transmitter will be developed in library transmitter, the receiver will be developed in library receiver, the utilities will be collected together into a library called utilities and then the whole system will be assembled in library system. A quick check with Appendix B.2 confirms that none of these names is a VHDL keyword.

Consider the designer working on the transmitter section. That designer will set their work library to point to library transmitter. Another designer working on the receiver section of the design will set library work to receiver.

This organisation allows the two designers to work independently. Both will have access to the contents of the utilities library and the placement of components in that library will have to be managed between them, but the design work in the two main system libraries transmitter and receiver can go on in parallel. When the two subsystems are complete, or at least complete enough to try assembling a prototype, the system components can be written, incorporating the two subsystems as components in the design. There is no need to copy any of the source code of the two subsystems because their libraries can be used directly in the completed design by referring to them by their names. Thus, the top-level design unit for the receiver can be used as a component in the overall system by simply referring to that component in library receiver.

The only difficulty here is when to refer to a library as work and when to refer to it by its name. In general, all subcomponents of a subsystem should stay together in one library. They can refer to one another by referring to each other via the library name work. The name of the library should not be used if it is the same library as the design unit itself is in. This strategy means that a library can be renamed, for example to resolve a name conflict, and the only source code changes that will have to be made will be in the system design that refers to the library.

For example, suppose the transmitter has a package called transmitter_types and a top-level design unit called simply transmitter. It is good practice to give the top level of a design the same name, or at least a similar name, to its library. This acts as a reminder of which design unit is the top level. The top-level entity will look something like this:

use work.transmitter_types.all;

entity transmitter is

  port (a : in transmitter_data(15 downto 0);

  ...

In this case, the package has been referred to via the library name work rather than the library name transmitter because it is intended that the package should always be compiled into the same library as the entity.

The other special handling when referring to library work is the lack of a library clause. Library work is always available for use in a design, so it is not necessary to have a clause that says library work.

This organisation means that, if a library has to change name for any reason, the components within it will still refer to each other correctly and there is no need to change any of the source code. For example, all components in library receiver will refer to each other using the name work, not the name receiver.

14.4 Standard Libraries

There are two libraries that are standard and therefore will be part of any VHDL system that you are likely to use. These two libraries are called std and ieee. The set of design units found within each library is standardised. In the case of library std, the standard packages have remained much the same since VHDL was standardised in 1987, with only slight revisions to the packages themselves in 1993 and 2008. Library ieee by contrast has developed and now contains many packages that are applicable to synthesis. Only the synthesis-related packages will be described.

When using the VHDL-1993 compatibility packages to provide VHDL-2008 features to tools that don't support them yet (see Chapter 6 for an explanation), you may also use a temporary library called ieee_proposed. Everything in ieee_proposed will eventually be merged into library ieee.

14.4.1 Library std

Library std is an integral part of the VHDL standard and is so essential that there is an implicit library clause referring to it for any design unit that you compile. This means that you never need a library clause to library std.

There are two design units in library std.

package standard

package textio

Package standard defines the basic set of standard types. The package is listed in Appendix A.1.

Package standard is so integral to the language (for example an if statement must have a boolean expression) that there is an implicit use clause for every design unit that you compile making package standard available for that design unit.

To summarise, there are two implicit clauses before every design unit that are equivalent to the following VHDL statements:

library std;

use std.standard.all;

It is never necessary to state these explicitly and it is recommended practice not to state them.

Package textio is also part of library std. This is a text I/O subsystem that allows files to be read or written and reports to be printed to the screen. It includes overloaded read and write operations on the standard types defined in package standard. It has no direct use for synthesis, since there is no way of synthesising such I/O operations. However, it is extensively used in the development of test benches, as described in Chapter 13.

14.4.2 Library ieee

Library ieee is a library containing IEEE-standard design units that form extensions to the language for certain application-specific areas. Since it is not integral to the language, there is no implicit library clause for it, so you have to use an explicit library clause:

library ieee;

There are six standard synthesis-related packages in library ieee, all of which have been described in previous chapters but mostly in Chapter 6. These are:

package std_logic_1164

package numeric_bit

package numeric_std

package fixed_float_types

package fixed_pkg

package float_pkg

The first design unit to be added to library ieee was the package std_logic_1164, so-called because it contains the definitions for the standard logic type std_logic and because the package was originally defined by IEEE standard number 1164, though it is now part of the main VHDL standard. Nevertheless, it is a rather clumsy name and a completely unmemorable number. It would be interesting to know how many other standard logic packages the design committee were anticipating when they decided to include the standard number in the name! Fortunately, you will type this name so often that it will either become second nature or an editor macro.

Package std_logic_1164 was described in Section 6.3 and is listed in Appendix A.3.

Packages numeric_bit and numeric_std were described in Section 6.4. They are alternative implementations depending on which base type you use for logic modelling. Package numeric_bit is rarely used and is not recommended, whilst package numeric_std is listed in Appendix A.5.

Both fixed_pkg and float_pkg use the supplementary package fixed_float_ types to define their rounding modes. This package is listed in Appendix A.7.

Package fixed_pkg was described in Section 6.5 and is listed in Appendix A.8.

Package float_pkg was described in Section 6.5 and is listed in Appendix A.9.

All other synthesisable design units in library ieee are non-standard and shouldn't be there now that the numeric packages have been standardised. However, there are some packages that are often found there for historical reasons. It will take some time for these packages to be phased out because of the number of designs already in existence that use them. These are:

package std_logic_unsigned

package std_logic_signed

package std_logic_arith

package std_logic_misc

package std_logic_textio

Packages std_logic_unsigned and std_logic_signed are rather obsolete bitwise arithmetic packages. Together they are roughly equivalent to std_logic_arith but they have a fundamentally flawed design that makes them virtually unusable in practice. They should never be used and will not be covered in this book. The package std_logic_arith is a proprietary package to Synopsys Incorporated, but is available in the majority of VHDL systems since Synopsys made the wise decision to make the package public domain, thus ensuring its widespread use. It is very similar to numeric_std and indeed was the model for it, although the design committee probably wouldn't admit this. It was covered in Chapter 7 but its use is now deprecated. New designs should use numeric_std in preference. Package std_logic_misc contains some assorted utilities that extend the functionality of std_logic_1164 slightly. Finally, std_logic_textio extends I/O to the std_logic_1164 types. It has also been made obsolete by recent development and its use is also deprecated.

Any other packages found in library ieee are non-standard (neither IEEE-standard nor de-facto standard) and shouldn't be there at all. The exceptions are the packages standardised for the IEEE VITAL standard, which is a standard that addresses the issue of gate-level simulation. VITAL defines a standard way of writing gate libraries such that they can be automatically back-annotated with timing data to give accurate timing models during gate-level simulation. They are not relevant to the RTL design stages used up to synthesis and so are outside the scope of this book.

14.4.3 Library ieee_proposed

Library ieee_proposed is a library containing proposed IEEE-standard design units that form extensions to the language. In particular, it can contain VHDL-1993 compatibility versions of the new VHDL-2008 synthesis packages described in Chapter 6, plus additions packages containing additions to the existing standard packages. Since it is not integral to the language, there is no implicit library clause for it, so you have to use an explicit library clause:

library ieee_proposed;

If you are using these VHDL-1993 compatibility packages then the following synthesis-related packages will be compiled into this library:

package standard_additions

package std_logic_1164_additions

package numeric_std_additions

package fixed_float_types

package fixed_pkg

package float_pkg

The additions packages add the missing I/O and string formatting functions used in test benches as described in Section 13.11. The last two packages are the VHDL-1993 versions of the fixed-point and floating-point packages for systems that don't yet provide them in VHDL-2008 form in library ieee.

14.5 Organising Your Files

It is common practice and good sense to have all the source files for all the design units in a library stored in one directory. The library mapping file containing the library dependencies for that set of design units can then go in the same directory. Furthermore, the library itself is usually also stored in that directory (as a subdirectory that is) so that whenever any changes are made to the contents of a library, all the pertinent information can be found in one place.

When using both synthesis and simulation from different vendors (and sometimes even with the same vendor), two libraries will be needed. The internal format of a library is vendor-specific and also usually tool-specific, so a library for the simulation system will not be usable with the synthesis system. Indeed, a library for one simulator cannot be used with another simulator. You will need to compile all source files with the simulator and the same set of files excluding the test benches with the synthesiser. The two different versions of the library and the two library mapping files should still be kept in the same directory, using different subdirectories for the libraries. This organisation ensures that there is just one copy of the VHDL source code.

Just to illustrate this point, consider the filter design used earlier to illustrate the use of libraries to subdivide a task. In that example, there were four libraries: utilities, transmitter, receiver and system. Each of these libraries will be stored in a separate directory. A typical directory structure for such a project is illustrated by Figure 14.1.

Figure 14.1 Project directory structure.

img

In this example, all of the library directories are contained in one project directory. This is also good practice, since it keeps the whole project in one place, whilst at the same time allowing different designers to work on each of the libraries.

Consider the transmitter section and let's assume that this component has just two source files, transmitter.vhdl and memory.vhdl. This component uses subcomponents from library utilities as well as standard packages from std and ieee. Thus, there are three other libraries being used as resources in addition to the work library for this component. The contents of the design directory are illustrated by Figure 14.2.

Figure 14.2 Project subdirectory contents.

img

Both the simulation and synthesis libraries will have the same VHDL name, even though they are in different subdirectories. The simulation library will be stored in a subdirectory called simlib, whilst the synthesis library will be kept in a subdirectory called synlib. To avoid any vendor-specific details, I will assume that the simulator uses a library mapping file called simulator.map and the synthesiser uses a library mapping file called synthesiser.map.

The simulator's library mapping file simulator.map will contain a set of library mappings that includes the working library for the transmitter component, plus the three resource libraries used by this component. The resulting library mapping file looks something like this:

transmitter = ./simlib

utilities = ../utilities/simlib

ieee = /simulator/libs/ieee

std = /simulator/libs/std

work : transmitter

The synthesiser's library mapping file synthesiser.map will map the library name onto the synthesis version of the libraries:

transmitter = ./synlib

utilities = ../utilities/synlib

ieee = /synthesiser/libs/ieee

std = /synthesiser/libs/std

work : transmitter

This illustration included a mapping for library std and a mapping for ieee. Most VHDL systems do not require these mappings to be explicitly stated since these libraries are predefined as global libraries. Once again, bear in mind that there will be two versions of each library, one will be part of the simulator's setup, whilst the other will be part of the synthesiser.

14.6 Incremental Compilation

One of the additional advantages of the library system of VHDL, apart from the ability to work independently on different parts of a design, is that it allows incremental compilation.

Incremental compilation means that, if you make a change to a design unit, then it is only necessary to recompile that unit. All other units, which are unchanged, do not need to be recompiled.

This is a simplification, however. All design units are dependent on the packages that they use. If a used package changes, then all design units that depend on that package must also be recompiled.

Many VHDL systems, both simulators and synthesisers, will automatically calculate such dependencies and perform these dependent recompilations automatically. However, you as a designer can help to minimise the extent of such recompilations by the way that you manage your VHDL code.

When you add a use clause to a design unit, you are making that unit dependent only on the package header, not on its body. If you change the body, for example to fix a bug in one of the functions provided by the package, then recompiling the body only will avoid any dependent recompilations. On the other hand, if you change the package header, for example to add new declarations or to change an existing one, then it is necessary to recompile the header too. This will force the recompilation of all dependent units.

It is therefore good practice when working with packages to keep the source code for the header and the body separate. By this simple technique, the number and extent of recompilations can be minimised.

A similar dependency exists between entities and architectures. When a component is instantiated in an architecture, the component is bound to its entity by a configuration specification. This creates a dependency on that entity. If the entity is recompiled for any reason, then all architectures containing component instances bound to the entity will have to be recompiled. However, once again the architecture of that entity can be recompiled on its own without causing a recompilation of the dependent units.

Once again, you can minimise the effect of changes by keeping entities and architectures in separate files. Then only the minimum set of files will need to be recompiled if there are any changes.

This is why VHDL has separate primary units and secondary units. Changes to the primary units (entities and package headers) force recompiles of all design units dependent on them. However, primary units change relatively infrequently compared to secondary units. Secondary units (architectures and package bodies) can be changed and recompiled without forcing any recompilations of other design units. By keeping primary and secondary units in separate files, the impact of design changes on the compilation overhead of simulation and synthesis can be minimised.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset