Running a custom testbench with ngDesign

In this post I'm going to show you how to run a custom testbench in ngDesign. I will use the Sobel filter I've written as an example. The code is available in our Github examples repository, and I suppose you have followed the online course, are already familiar with ngDesign, and have imported the Sobel project from the examples.

Let's start by creating a run configuration for the entity that you wish to test. In our case, this is the sobel.SobelFilter entity. Right-click on the file and choose Run As > Cx Simulation.

Because this file defines two entities, ngDesign will ask which one you want to simulate.

I pick SobelFilter since this is the one I want to simulate, and hit Enter. The simulation runs, but doesn't do much at this point.

This is because the default testbench generated from an entity uses values from the test property: stimulus values are written to the entity's inputs, and the testbench reads output values and check them against expected values. In this case, we don't specify test values because we are going to use a custom testbench.

To do that, we must edit the Run Configuration that was automatically created when we launched the simulation. Click on the down arrow near to the Run icon, and click on Run Configurations... Alternatively, you can use the Run menu, or even by right-clicking on the SobelFilter entity in the Run As contextual menu.

The "Configuration" tab allows you to specify additional source files, as well as include directories and libraries. Admittedly this is perhaps not the best name ("Testbench" might be more intuitive, or "Custom test"). Anyway, the idea is that by default when you simulate an entity like the SobelFilter in this example, ngDesign generates the following files:

  • include/SobelFilter.h - defines structures with virtual functions
  • src/SobelFilter.c - implements the behavior of the application
  • src/SobelFilter.tb.c - defines the main function that initializes the application and checks its behavior with stimulus/expected values

Using a custom testbench is done by contributing custom files (at the moment only written in C/C++) that are used instead of the .tb.c file. You define the main function, you initialize the application yourself, and then you're free to give it the values you want, examine how it runs, etc.

In this example, I've written my custom testbench in a single C file "sobel_filter.c" in the "demo" directory at the root of the Sobel project (in general I favor C over C++ because it is much simpler and to the point, but that's a matter of taste). Add the file using the "Add source file..." button. The test uses SDL so you need to specify an additional include directory to the library as well as libraries. These are platform-dependent, on Windows you can put the folders wherever you want, whereas on Linux the library is usually installed in a standard place.

Finally, set the working directory to the "demo" folder as this is what the code expects to look for the input image. Hit Run and...

voilĂ ! The testbench displays two images side-by-side, one is the original image (the famous Lena), and the other one the image filtered by the SobelFilter application. If you look closely you can notice artifacts in the top and left edges. This illustrates perfectly the advantage of this kind of visual testing (as opposed to simple text-based tests), it makes it much easier to spot errors :-)

So what's next? Well the Sobel application is open-source, so don't hesitate to hunt the bugs and send me a patch or pull request!