cover story
VHDL is an extremely powerful language that, when used correctly, can significantly decrease your overall design cycle time. As with other hardware description languages, VHDL can represent tens of thousands of gates in a few lines of code. This abstraction alone can yield faster design cycles. But VHDL offers another significant advantage: the ability to reuse entire designs or portions of designs in other designs. Reuse allows you to focus on innovation rather than on reinventing the wheel. However, you must follow some guidelines and make a few trade-offs in writing reusable code. Proper employment of control files results in VHDL code free of tool-specific directions; hierarchy and partitioning determine the most useful block sizes; precise comments, simple interfaces to other modules, and test benches all enable an easy fit with future designs. Perhaps most critically, generics enable you to customize modules without having to change the underlying VHDL code, to speed synthesis and simulation cycles, and to make quick changes to design parameters and even to entire feature sets. The main pitfall occurs when a synthesizer tries to merge two modules and ends up with a new and sometimes incorrect equation, but careful monitoring at the synthesis stage can mitigate such difficulties. Overall, writing for reuse can save hours of future work while providing consistency across all your designs. Know your synthesizer Although VHDL is an IEEE standard that is widely accepted by many tools, each tool contains its own set of knobs and switches that are meant to help you achieve the desired performance and logic utilization for a given design. These benefits, however, complicate the production of reusable code. The workaround, fortunately, isn't too difficult to accomplish. To write truly reusable code, you should try to minimize the amount of tool-specific directives that you place in your VHDL file. Most tools have the capability to put these directives in a separate file, sometimes known as a control file. Certain tools also let you customize the options selected for a given synthesis run in a script file or project file. These capabilities are important to understand if you intend to reuse your VHDL code in the future. Separating your VHDL description from your tool-specific synthesis directives allows you to reuse the code with another synthesizer or target technology if necessary. A simple example of a synthesis directive that could be placed in a control file would be a state-encoding attribute. When synthesizing state machine logic into a device--especially an FPGA or a CPLD--you typically need to specify some kind of state encoding. Depending on the target architecture of the device, the state encoding could vary drastically to obtain optimal results. In general, FPGAs are better suited for "one-hot" state encoding (a traditional coding style that assigns one set of registers per state). CPLDs can implement much more logic per register, so they prefer sequential state encoding. In any case, you can use your VHDL code to describe the function of the state machine using enumerated types and then place the state-encoding directive in a control file. A control file in one synthesis environment looks like this: --State-encoding directive for VHDL
Hierarchy Hierarchy holds the key to writing good reusable VHDL code. Deciding where to partition the design is critical. Frequently, making a top-level design nothing more than a netlist of lower-level modules helps you to visualize the overall circuit. Some development systems can graphically connect lower-level VHDL modules using symbols in a schematic capture tool. These development systems can automatically create symbols from VHDL modules and instantiate them in a top-level schematic, combining VHDL with other schematic gates. Other things that might belong in the top level (whether written in VHDL text or captured with a graphical tool) are three-state buffers, input registers, and output registers. One step down the hierarchy from the top level would be the primary functional blocks. At that level, your design might contain many--or just a few--different blocks working in parallel, the number depending on the overall size of the design you are describing. The lowest level of the hierarchy should consist of modules that are manageable in size. It's difficult to provide a rule-of-thumb for what is manageable, but 2,000 to 5,000 gates is a reasonable range.
Once you've partitioned your design into smaller chunks, you should think about which modules would be useful for future designs and which are very specific to this particular one. The modules that seem likely to apply to other designs require special attention. Some examples would be a state machine that controls powerup/reset circuitry, a PCI interface to another bus, and address-decoding logic. Crafting these modules with some forethought is the key to enabling their reuse. What makes code reusable? Many functions can be recycled in future designs, so it's worthwhile to spend some time and energy in making VHDL code as simple and as readable as possible. It's impossible to identify the types of circuits that are more often reused than others, and frequently you don't know what your next design will need until you begin working on it. It is thus important to treat every VHDL module you write as a candidate for future use.
Good comments are a must. This discipline is important for any design, but it's especially critical for a module intended for reuse. Specifying and verifying the exact behavior of a module allows the next designer to worry about only the interface to the code and not the code itself. Thorough documentation also helps you remember the function of the module months after the design is in production. A good strategy for adding comments to your code is to start with writing down the intent of the module itself. This practice captures some of your thought process as you sit down to write the VHDL itself. Then you should state the purpose of each signal defined in your module, including those listed in your entity's port declaration as well as any local signals or variables. Finally, make sure you document the algorithms and data flow of the circuit in as much detail as possible. Reusable VHDL code also requires a simple interface to the rest of the design. Reducing the number of inputs and outputs in each module to their absolute minimum increases its overall usability and ease of integration. Another seemingly obvious, but often ignored, rule of thumb is to group common signals together in your entity port list, a practice that aids in making modifications to the VHDL module in future designs and improves the overall readability of the VHDL code. Finally, it's extremely useful to create a test bench for the design module. A test bench not only aids you in debugging your code, but truly captures for future use the intended and specified behavior of your circuit. A good test bench should exercise the circuit in every way possible to catch any functionality problems that lie outside of the normal operating conditions. Once your VHDL description passes your test bench, you should rerun the postsynthesis simulation model through the same test bench to see if the synthesized circuit still operates the way that you originally intended. A proper test bench is a powerful means to communicate the exact operation of a VHDL module. Using VHDL blocks acquired from other designs or possibly even other companies has its drawbacks. Merging your VHDL design files with other VHDL modules isn't always as simple as it sounds. The first challenge is to understand the external module well enough to interface seamlessly to it from the rest of your design. You should spend time simulating the external block of code independently before you merge it with the rest of your circuit. Once you're familiar with the operation of the VHDL block, you may need to customize its behavior for your needs. If you aren't using customized modules, however, you must dig in and modify the VHDL code itself. Integrating VHDL modules into a single design requires attention to how your synthesizer handles the interface between modules. Often, each module alone simulates and synthesizes correctly but doesn't work as expected when connected to another. This typically results in slower performance or much higher gate usage than necessary. The culprit is combinatorial logic at the output side of one module feeding more combinatorial logic at the input side of another: the two modules become a single combinatorial circuit that's likely to be synthesized differently. If this shift occurs, you must direct your synthesizer not to combine that logic and to instead treat each set of combinatorial equations separately. Some programmable logic synthesizers frequently perform this task automatically, but in some cases you must apply the synthesis_off directive to a particular signal.
The figure shows a simplified example of this type of behavior, an adder (module A) feeding a comparator (module B). Once these two circuits are connected together, the synthesizer attempts to merge the logic and implement the new design in a single pass of gates, in effect blowing up the equations required to implement such a circuit. The example circuit was synthesized and placed into a CY37256 (256-macrocell) CPLD. Listing 1 presents the lower-level descriptions of the two individual blocks, and Listing 2 is the top-level VHDL description. The results show that the circuit performs faster if you apply the synthesis_off directive between module A and module B, but takes more resources to implement. Every synthesizer exhibits such limitations at some point, but the condition may not be easy to detect. It's best to synthesize each submodule independently to determine the number of gates and the maximum delay for that circuit. Then when connecting one submodule to another, you can synthesize the combined circuit and compare the area and speed results with the two previous results. In general, the combined circuit shouldn't take significantly more area than the addition of the two gate counts of the individual circuits. The maximum delay is a bit more difficult to predict, but your knowledge of the circuit's behavior, along with the architecture of the target device, should provide a clue to the desired performance. In cases such as this example, you may need to trade area for speed, and only you--the designer--can make that trade-off correctly. Customized modules An extremely useful and unique feature of VHDL is the ability to customize a particular module without having to modify the underlying VHDL code. This feat is accomplished through language parameters known as generics. A generic in VHDL is a mechanism for passing parameters to a module in order to change its behavior. A generic can be as simple as a vector width or as complex as a switch that changes an entire circuit. Understanding how generics work and using them to your advantage can greatly increase your design reusability. An existing module might be mostly useful in your new design, but it now requires more features, or a greater bus width, or some other fundamental change. Considering such possibilities while you're designing can ease the integration of your modules into future designs. A generic is defined in the entity portion of your VHDL description, and includes a port list that defines its parameters and their associated types. When designing a customized module, you must associate default values with your generics. Once your entity and architecture descriptions are complete, you can place them into a component and then into a package for future use. You then instantiate this component in a higher-level VHDL file, assigning the proper port connections and the generic values to each previously defined generic. Any generic not assigned a value at the time of instantiation takes on the default value given in its entity description. A VHDL entity can define as many generics as needed. Generics can also be passed from higher-level to lower-level modules. This flexibility allows you to create a parameter in the top-level design that can be passed down to multiple modules at the lowest level of the hierarchy. Now you need to change just one parameter to breathe new life into your entire circuit. The very simple example in Listing 3 describes a "generic" counter that can be configured to any width. The counter itself has a default width of 16, but this value can be changed whenever the circuit is used. In fact, the actual width of the counter is not specified until the module is instantiated in another VHDL module, allowing you to use the module wherever you need a counter, regardless of the width. In this manner, you can pass any type of generic to a VHDL module and change its behavior without modifying the VHDL code itself. A generic can specify bus sizes, reset values, or address locations, or even change the algorithm of your entire circuit. Generics can also speed up synthesis and simulation cycle times. For example, suppose that synthesizing and simulating a 32-bit counter takes hours. Generics allow you to instantiate a 4-bit counter instead, evaluating its behavior until it works. Then you can increase its size to 32 bits and perform your final synthesis and simulation run. You can thus synthesize and simulate the design while it's small, saving time, and then simulate your large design after you have worked out all of the functional bugs. Generics also allow you to easily describe a circuit that includes a multitude of bells and whistles that may or may not become part of the final design. A generic enables you to "turn off" these extra features and then turn them back on late in the design cycle without modifying your underlying VHDL code. You can feel confident that the module itself will work in multiple configurations because you can simulate and synthesize them ahead of time. In this fashion, you can create a circuit that adapts to your market requirements at a moment's notice. This same circuit can then be utilized in another design with a different set of features, in effect allowing you to design an entire line of related products with a single set of VHDL modules using different generic parameters. Richard Kapusta, design tool applications manager at Cypress Semiconductor Corp. in San Jose, is responsible for the direction and definition of the Warp programmable design tools. He previously worked as an applications engineer for Cypress's programmable logic division. He has five patents on CPLD architectures. To voice an opinion on this or any Integrated System Design article, please email your message to miker@isdmag.com. integrated system design October 1998[ Articles from Integrated System Design Magazine ] [ ICs and uPs ] [ Custom ICs and Programmable Logic ] [ Vendor Guide ] [ Design and Development Tools ] [ Home ] For more information about isdmag.com email webmaster@isdmag.com For advertising information email amstjohn@mfi.com Comments on our editorial are welcome. Copyright © 2000 Integrated System Design |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Home | About | Editorial Calendar | Feedback | Subscriptions | Newsletter | Media Kit | Contact | Reprints| RSS|
Digital| Mobile |
| Network Websites |
|
International |
|
Network Features |
|
|
|
All materials on this site Copyright © 2009 TechInsights, a Division of United Business Media LLC All rights reserved. Privacy Statement | Terms of Service | About |