From the very first day that you learn a new hardware description language (HDL), you reuse code. Initially, this might involve copying an example and modifying it in order to learn and expand your knowledge. Later, you start looking for common blocks of code so as not to re-invent the wheel. Alternatively, you could decide to reuse an entire design and recode parts of it to create a variant.
Despite the good efforts of the design community to espouse design-for-reuse as the Holy Grail, what many engineers – including thousands of FPGA designers like you worldwide – do in reality is recycle code. This is no disgrace. Actually, it is very smart. Recycling allows you to quickly fill up those monstrously large FPGAs with blocks of code from previous designs, IP, and your own custom code.
While recycling has its advantages, it is recommended that you follow a solid recipe for success in order to evaluate recycled code before using it within your new project. If you do not follow these simple steps, all the time you thought you would save by recycling the code in your new FPGA could easily be lost trying to get it to work correctly.
This is practical reuse – a working recipe for getting your next design quickly completed by reusing code that already exists at your corporation. And, you will likely find that looking at the problem from a completely different angle will actually lead to more and more reuse in your next projects.
Practical reuse is a discovery process performed with or without tools. This process includes the following steps:
- Determine design integrity: Is the code complete and do you understand (at a high-level) what the code does?
- Determine code quality: Can the code be easily reused and does it meet any standards you might have?
- Establish design validity: Does the design simulate and function as expected?
- Share knowledge: Does everyone in your company have access to the design?
Determine Design Integrity
Design integrity fundamentally means that all the code is complete and ready for simulation. Typically, the first step is to find the top level of the design in order to ascertain which files comprise the RTL description from the root of the design on down. Additionally, you can eliminate any extraneous HDL files from the project. The numerous output files created by your FPGA vendor tools actually can get in the way of your discovery process. You do not need these files in order to reuse the HDL code in your next FPGA design.
Next, if the design is under version control, you will need to check out the latest version of the design and review history notes before starting the discovery process.
You can start with a manual technique, looking for a top-level "readme" or document file that might describe the design file hierarchy. Or, look for a compilation script for clues to design content. Finally, look for a file with an obvious name like "top" or a file that contains many component instances and no logic. As you work with the files, take note of modules containing structure but no logic, as you will have to find or create this logic yourself.
Taking the analysis up a level, if you possess a tool that parses and determines hierarchy as part of the process of specifying code or performing an analysis, that tool can typically figure out the topography of the design and whether anything is missing. Also, parsers provide you with syntax and semantic checks that could reveal problems with the code. Examples of these types of tools are code visualizers, synthesizers, or simulators. Visualization tools also help you understand the design composition and what the design does.
Typically, FPGA vendor flows encourage the use of technology-specific IP or cells. These technology-specific components are often instanced with the HDL and handled by the downstream tools. You could find that these instance references are broken or that you do not have access to included files that define them. If you are targeting a new technology or a new FPGA vendor, these instances could greatly affect the amount of time that it will take to reuse the code – because you have to replace them.
At this point, you are ready to consider the "Practical Factor" for the first time in the process (Equation 1). You can incrementally refine and use this value as an initial checkpoint during the reuse process:
The ultimate goal, of course, is to reduce the denominator to zero, even though this can never actually happen. As we will discuss later, it is best to measure time in minutes or to convert hours to minutes. This is because units of time such as days, weeks, and months can be interpreted differently between people (for example, does a day represent 8 hours or 24?).
The TimeScratch variable is the hardest to estimate. You can employ various techniques to make a best guess:
- Get the total line count and apply a time factor in minutes for each comment (typically a low number) and for each non-commented line of code (typically a higher number).
- Alternatively, use historical time data from a similar project that you may have recently worked on.
- If you use generators, the time it takes to create blocks of the design decreases dramatically. For example:
- High-level graphical tools (like block diagram and FSM editors) generate code for you.
- Platform-based tools allow you to drop in microprocessor cores, their compatible bus structures, and peripheral blocks – thus generating even more code for you.
- Electronic system level (ESL) tools allow you to design at a very high level and generate RTL as well.
Regardless of the technique, you also need to factor in the time it takes to verify the code. That topic is covered later in this article.
At this point, the TimeReuse variable represents TimeIntegrity, which comprises the following:
- The time it takes to correct any syntax errors (typically quick to fix) and semantic errors (typically longer to fix) that you found. Multiply each syntax error times a minute factor and each semantic error by a higher minute factor.
- Add in the time it will take to create any missing blocks of functionality that you found, using one of the previous TimeScratch techniques. This includes the time it will take to re-map FPGA technology-specific instances in the code.
- Add together the time it took you to understand the design and to figure out the top level of the design as well as the design topology.
Thus you now arrive at the second checkpoint (Equation 2):
If the Practical Factor approaches 1, you would obviously stop now, as reusing this design would take as much time as it would take to create it from scratch.
Determine Code Quality
Assuming that the code has passed the previous checkpoints, quality is the next consideration. A good place to start is with the Quality IP (QIP) matrix and user guide provided by the folks at VSI Alliance (VSIA). The QIP is a spreadsheet that lets you leverage collective knowledge about how reusable your code is. You manually enter answers to questions and a weighted score is produced. If the score is low, it could take a lot of work to reuse this code. (You can visit www.vsi.org to obtain more details about the QIP matrix.)
In order to automate code quality assessment, you can use a code checker (sometimes called a linter). Often, these checkers have built-in rulesets for the major FPGA technologies. Run the appropriate technology rules on the design to evaluate the results. If you do not have access to a tool with built-in FPGA rules, the tool most likely has a common reuse set of rules that you can run.
Companies also capture rules that represent collective knowledge about code that can cause downstream design errors. Activate these rules separately and run the tool to assess reuse and quality. Some checkers also support the RTL QIP checks or allow you to weight and score your own rules. These checkers can also detect empty blocks for you.
At this point, TimeReuse represents TimeIntegrity (from our previous checkpoint) + TimeQuality:
- Multiply each FPGA technology (or reuse) violation by a time factor in minutes.
- Multiply each downstream violation by a larger time factor in minutes.
- If you found any additional empty modules using the checker, factor in the time to create them back into the TimeIntegrity value.
This brings you to the next checkpoint (Equation 3):
Is the number getting closer to 1? If not, proceed to the next step.
Establish Design Validity
After you determine the code integrity and quality, it is time to decide if the design works as expected. At one extreme, you could program the new FPGA with the reused code and see if it works out in the lab. However, that is probably not practical. Typically, a better approach is to verify the HDL code using a simulator. Design verification can be a complex process that uses several techniques and tools.
First, account for validation time in the denominator of the Practical Reuse factor. This value should be significantly less than creating a test environment and running validations from scratch. Taking a simplistic approach, estimate a time value for each of the following:
- Does a testbench exist? If not, you will have to create or generate one, and that will take time.
- Does the testbench contain many tests? If not, you will have to add testing routines to it to ensure acceptable coverage.
- If you have the ability to run code coverage, does the testbench exercise the entire design? If not, you will have to upgrade the testbench.
- Do the testbench and the RTL contain assertions? If not, debugging time will increase.
- Do you get simulation errors? Each one will take time to debug.
- How much time do you actually spend simulating? You need to account for this time as well.
How you account for the significant time spent addressing the preceding issues is based on your experience. Establish a TimeReuse Validate value by multiplying an estimated time factor to each of the preceding issues. Then add the total value to the denominator of the Practical Factor equation.
Next, don't forget to account for the time it would take you to create tests and run the validation from scratch. For a rough estimate, you can use the "70% of the design cycle is spent in verification" claim of lore. Assume that this 70% means creating and running tests as well as correcting problems. That means 30% of your time is spent doing something else. If you assume that 20% of that "something else" is design creation, then multiply your value for TimeScratch by 3.5 to get a value for Timescratch validate. Add this number to your original TimeScratch value to get the "final" TimeScratch estimate (Equation 4).
Does the Practical Factor indicate that the code is still viable for reuse?
Share Your Knowledge
Even if the design failed to pass the checkpoints discussed above, the upside is that it is still good knowledge to share within a team or corporation. Otherwise, someone else might discover the code and spend time trying to reuse it. Also, there could still be blocks of code or data that could help a colleague.
A good approach to sharing is to create a high-level website that contains a list of designs available for reuse. At the top level, enter a brief design description and add your comments on the Practical Factor checkpoints so that everyone knows its status. Then create (or use a tool to generate) a web page for each design and collate the following information from your discovery process:
- The RTL source, including the testbench (leaving behind any source that is not part of the design).
- Any notes or drawings that you generated or created by hand during your discovery process.
- Documents and scripts that you found useful.
- Your integrity, quality, and validation notes or reports.
Encourage others to view your website and to contribute to its content. To start off, let your colleagues and immediate co-designers (and ultimately remote teams and the corporation) know about the effort so that the top-level web page becomes a useful central reuse repository.
Until everyone designs for pure reuse, the need for practical reuse will exist. Establishing your own practical reuse recipe now will encourage a new method for thinking about the problem and will allow you to identify tools you need to automate the process. As you work with automation techniques and tools, you will gravitate towards a design flow that naturally enables developing code for reuse. Eventually, you will realize that you are actually designing new code for reuse as an effect of employing practical reuse techniques.
Tom Dewey is a Technical Marketing Engineer for the HDL Designer Series product line at Mentor Graphics. Tom has over 17 years of EDA experience, contributing to ASIC and FPGA software products used for creation, synthesis, verification, and test. Tom can be reached at firstname.lastname@example.org.