Reusable VHDL IP in the Real World
By Matt Bridle, RF Engines Ltd.
Reuse has been an industry buzzword for years now. It is hardly a new idea, and probably goes back as far as the time when man first realised he could use the same fire both for keeping warm and for roasting his sabre‐tooth tiger ribs. When it comes to IP, reuse can be an extremely powerful way of saving resources and shortening project timescales.
At RF Engines, we find that reusing existing IP is very desirable. Not only does it save us development time and help us fulfil challenging delivery requirements, but making use of pre‐proven components also helps give customers confidence in our designs.
Another dimension to this is that multi‐FPGA designs are becoming increasingly widespread, and there are obvious advantages to having a chip‐level infrastructure that is reusable within the project.
Reuse, then, is clearly A Good Thing. However, in practice it has often proven surprisingly difficult to achieve. So it is worth bearing in mind a few principles and techniques that can be applied to make it more straightforward. Though it would be foolish to say that creating reusable VHDL doesn’t require any extra effort, it frequently pays significant dividends in the longer term.
Thinking ahead
At the beginning of implementation, thinking about what else your component might be useful for in the future may not be the first thing on your mind. Sometimes it’s not obvious that your component has multiple applications, and that reuse should be one of your design goals. But even when you don’t know what the component might be useful for in the future, if you take a step back, it’s often easy to see a few aspects of the design which can be written in a flexible way without too much of an overhead.
Wisdom from Kylie
You may spot an existing piece of your IP that you can re‐use with some adjustments for a new application, but that wasn’t designed for reuse in the first place. However, as that great Australian philosopher once said, it’s never too late – we’ve still got time. There is a temptation to simply copy the old design and change it, and sometimes – if the changes are complex and pervasive – this is a good option. But often, you can take the existing IP and revise it to make it more flexible – though of course some regression testing is needed to make sure you don’t break it in its original setting.
The nitty gritty
One issue that often arises in design for reuse is that many of the language features which make design for reuse easier are software‐style constructs. Hardware engineers may be wary of these constructs as they can obscure the relationship between the VHDL and the resulting implementation, but if used carefully they can be a great help. Here are a few examples.
Using a generic to set parameters such as the width of entity ports is common practice. It not only makes the component easier to reuse in other circumstances, but helps to document the code, since a meaningful generic name can be used instead of an apparently random number.
Any code which depends on the width of such ports or signals then also needs to be parameterised on the generic, e.g. to produce a reduction‐and of data_in above:
Generics are also useful to make different variants of a component. You can add a boolean generic and use an if generate statement to implement optional code, rather than writing a different variant of an entity.
Another useful trick is to gather collections of signals together using arrays. Signal processing applications often operate on blocks of data at a time, and the operations often have a strong regularly structure. Using arrays in this context can help extensibility and readability. For example, say you want to instance several copies of an entity to perform a signal processing operation, each working with one of a number of parallel data streams. You could write this as:
The width of the data vectors, or the number of vectors in a collection, can be changed simply by altering the relevant constant. Notice also the use of the ‘range attribute, which yields the range of an array type, variable or signal. You could alternatively just use the explicit range 1 to collection_size instead of collection_type’range, but it’s a little more restrictive as it assumes that collection_type’s range starts at 1. Commonly in a signal processing application, once you have operated on each element of your data block, you will want to perform another operation on the results. For example, you could sum the results of from all the operations above using a process such as:
This is again very flexible as it doesn’t rely on knowing the data width or number of results. The ‘range attribute has been used again, this time to help us create an unsigned vector of the same dimensions as data_vec (which is a std_logic_vector). Of course, the code above could produce a very large adder chain and so in practice a more sophisticated pipelined architecture would almost certainly be necessary.
There are a couple of pitfalls to watch out for in this example. One is that VHDL requires the element type (data_vec) of the array (collection_type) to be globally static. That unfortunately means you can’t use a generic to parameterise both the width of data_vec and the size of collection_type (hence the use of constants instead). In fact, collection_size could be a generic in the example, but data_width could not. There are various ways to get around this but none are perfect. One is to use a twodimensional array, which many synthesis tools now support. In this case, if we wrote:
then both collection_size and data_width could be generics. This can make it a little messier to access the data “rows”, so it is a trade off of flexibility against simplicity.
One other issue in this area is that, if data_collection_in/out had been entity ports, many synthesis tools would have broken them up into separate vectors, which could cause incompatibilities when doing gate level simulation. If you are unwilling to take this hit, you could create a wrapper which assigns the array elements to individual ports at the top‐level.
A final tip for making design reuse easier is to put a component declaration for your block in a package. Usually, you would have to place a component declaration in every architecture where your block is to be used, but if you create a package which contains a component declaration, then you save yourself and subsequent users the hassle:
Users of the block then simply need to reference the package, instead of redeclaring the component:
Is it worth it?
So is design – or redesign – for reuse really worth the effort? It may seem like a lot of work at the outset, but it can bring significant benefits in the long term. Or, looking at it the other way round, if you don’t have reusable components, you could end up wishing you had. Remember, a stitch in time saves nine. A bird in the hand is worth two in the bush. Many hands make light work but too many cooks spoil the broth... well, you get the idea.
About the author
Matt Bridle holds an MA in Computer Science from the University of Cambridge. He has worked for RF Engines Ltd. since June 2008, as part of their digital design team creating high performance FPGA‐based signal processing solutions using VHDL. Prior to this, Matt was a Consultant at Doulos Ltd., where he taught and co‐authored training courses for the industry, specialising in VHDL design and verification as well as scripting in Tcl/Tk. He was also previously a Staff EDA Engineer at ARM Ltd., developing modelling tools and verification environments.
|
Related Articles
New Articles
Most Popular
- Streamlining SoC Design with IDS-Integrate™
- System Verilog Assertions Simplified
- System Verilog Macro: A Powerful Feature for Design Verification Projects
- Enhancing VLSI Design Efficiency: Tackling Congestion and Shorts with Practical Approaches and PnR Tool (ICC2)
- PCIe error logging and handling on a typical SoC
E-mail This Article | Printer-Friendly Page |