9.2. The Embedded Processor as a Test Generator
Even if you don't plan to use an embedded processor core in your final FPGA implementation, using an embedded FPGA processor can greatly enhance your ability to test and debug individual components of a complete FPGA-based application.
There are a number of ways in which C code running on an embedded processor can act as an in-system, software/hardware test bench, providing test inputs to the FPGA and (if necessary) validating the results and obtaining performance numbers. When used as part of a complete testing and debugging strategy, the embedded processor becomes an excellent vehicle for in-system FPGA verification and a good complement to hardware simulation.
By extending this approach to include not only C compilation to the embedded processor but C-to-hardware compilation as well, it is possiblewith very little effortto create high-performance, mixed software/hardware test benches that closely model real-world conditions.
One key to such an approach is to make use of standardized interfaces between test software (C-language test benches) running on the embedded processor and other test components (as well as the hardware under test) that are implemented in the FPGA fabric. These interfaces should be designed to take advantage of communication channels available in the target platform. For example, the MicroBlaze soft processor provided by Xilinx has access to high-speed serial interfaces (the FSL bus) that provide a high-performance data channel to the FPGA fabric. This interconnect channel provides much higher performance data transfers than the more general-purpose OPB bus, which is also available to MicroBlaze users. Other FPGA families and embedded processors have different mechanisms for processor-to-FPGA communication, and these mechanisms should be studied carefully before developing a mixed hardware/software application.
By using such interfaces along with a unit test philosophy, it is possible to quickly verify components of a larger application and to apply inputs that test the boundaries (or corner cases) of each component, thereby improving the quality of the application as a whole.
A Unit Test Philosophy
An important aspect of hardware/software testing is to create unit tests for critical modules in an application. Using HDL simulators, for example, it is relatively easy to create test benches that will exercise specific modules by providing stimulus (test vectors or their equivalents) and verifying results. For many classes of algorithms, however, such testing methods can result in very long simulation times or may not adequately emulate real-world conditions. Creating an in-system, prototype test environment is an excellent way to enhance simulation-based verification and insert more complex, real-world testing scenarios.
Unit testing is most effective when it focuses on unexpected or boundary conditions that might be difficult to generate when testing at a system level. In an imaging processing application that performs multiple convolutions in sequence, for example, you may want to just focus your efforts on one specific filter by testing pixel combinations that are outside the scope of what that filter would normally encounter in a typical image. For many such applications it would be impossible to test all permutations from the system perspective. The unit test allows you to build a suite of tests to validate specific areas of interest or test only the boundary/corner cases. By performing such tests using actual hardware (which may for testing purposes be running at slower-than-usual clock rates), it is possible to obtain real, quantifiable performance numbers for specific application components.
Key to this approach is the ability to quickly generate the test bench software that will run on the embedded processor and to generate any necessary prototype hardware that will operate within the FPGA to generate sample inputs. By using C-to-RTL compilation it is possible to generate such mixed software/hardware test routines with a minimum of effort.
Desktop Simulation Versus Embedded Test Benches
As you've seen in the preceding chapters, a major advantage of using a C-based approach to hardware design is the ability to create software/hardware models for the purpose of algorithm debugging in software, using standard development environments such as Visual Studio. In this approach, the complete application (including the unit under test, the producer and consumer test functions, and any other needed test bench elements) is described using C, compiled under a standard desktop compiler, and executed, perhaps under the control of a source-level debugger.
When we apply a similar philosophy to embedded testing benches, we are somewhat limited by the constraints of the platform target. It may be difficult, for example to create a test in which files are read from and written to a disk drive, or to create interactive tests, as is possible in a desktop simulation environment. As you will see in a later chapter, however, the addition of a lightweight embedded operating system to the embedded processor can greatly simply the creation of complex and powerful embedded tests.
Data Throughput and Processor Selection
When considering processors for in-system testing, there are a few important considerations. First, consider the fact that an embedded soft processor requires a certain amount of area in the target FPGA device. If you are only using the embedded processor as a test generator for a relatively small part of your complete application, this added resource usage may be of no concern. If, however, the unit under test already pushes the limits of utilization in the FPGA, you may need to move into a larger device during the testing process and/or choose an FPGA that includes an embedded hard processor such as the Xilinx Virtex-II Pro or Virtex-4. These FPGAs include built-in PowerPC processors that add very little cost to the overall FPGA platform.
Another factor to consider when choosing an embedded processor is the synthesis time. Depending on the synthesis tool chain being used, adding a soft processor core to your complete application may add substantially to the time required to synthesize and map your application component to the FPGA, which might be a factor if you are performing iterative compile, test, and debug operations. Again, the use of a hard processor core has an advantage over the soft processor core when design iteration times are a concern.
If data throughput from the processor to the FPGA is your primary concern, you will probably find that using a soft processor (such as the Xilinx MicroBlaze with its FSL bus) provides the highest performance for streaming data between software and hardware components. By using the Impulse C libraries for hardware/software communication, the differences between these different FPGA-based processors and bus protocols can be abstracted (to a great extent) using a common set of stream read and write functions.
Moving Test Generators to Hardware
If the performance of test generation software routines must be further increased, the obvious way to do this is by moving critical test functions (such as stimulus generators) into hardware. Normally this is a tedious process of re-implementing using VHDL or Verilog, but by using automated C-to-RTL compilation you can very quickly generate hardware representing test producer and/or consumer functions that interact with the unit under test using streaming interfaces to implement test inputs and outputs.